From 911588b0d9cb91487e8f3fc0f8033f695a2970c2 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 1 Nov 2023 16:21:42 +0100 Subject: [PATCH 1/2] macroexpand: handle const/atomic struct fields --- src/macroexpand.scm | 24 +++++++++++++++--------- test/syntax.jl | 31 +++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/macroexpand.scm b/src/macroexpand.scm index e0e809eee08f1..e70bd24289361 100644 --- a/src/macroexpand.scm +++ b/src/macroexpand.scm @@ -343,6 +343,20 @@ (reescape '(escape ,ux) (cadr x))) ux) +;; type has special behavior: identifiers inside are +;; field names, not expressions. +(define (resolve-struct-field-expansion x env m parent-scope inarg) + (let ((ux (unescape x))) + (cond + ((atom? ux) ux) + ((and (pair? ux) (eq? (car ux) '|::|)) + `(|::| ,(unescape (cadr ux)) + ,(resolve-expansion-vars- (reescape (caddr ux) x) env m parent-scope inarg))) + ((and (pair? ux) (memq (car ux) '(const atomic))) + `(,(car ux) ,(resolve-struct-field-expansion (cadr ux) env m parent-scope inarg))) + (else + (resolve-expansion-vars-with-new-env x env m parent-scope inarg))))) + (define (resolve-expansion-vars- e env m parent-scope inarg) (cond ((or (eq? e 'begin) (eq? e 'end) (eq? e 'ccall) (eq? e 'cglobal) (underscore-symbol? e)) e) @@ -377,16 +391,8 @@ ((symbolicgoto) e) ((struct) `(struct ,(cadr e) ,(resolve-expansion-vars- (caddr e) env m parent-scope inarg) - ;; type has special behavior: identifiers inside are - ;; field names, not expressions. ,(map (lambda (x) - (let ((ux (unescape x))) - (cond ((atom? ux) ux) - ((and (pair? ux) (eq? (car ux) '|::|)) - `(|::| ,(unescape (cadr ux)) - ,(resolve-expansion-vars- (reescape (caddr ux) x) env m parent-scope inarg))) - (else - (resolve-expansion-vars-with-new-env x env m parent-scope inarg))))) + (resolve-struct-field-expansion x env m parent-scope inarg)) (cadddr e)))) ((parameters) diff --git a/test/syntax.jl b/test/syntax.jl index 17ade72112ec0..bc8418dadb072 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -1783,6 +1783,37 @@ end @test B28593.var.name === :S @test C28593.var.name === :S +# issue #51899 +macro struct_macro_51899() + quote + mutable struct Struct51899 + const const_field + const const_field_with_type::Int + @atomic atomic_field + @atomic atomic_field_with_type::Int + end + end +end + +let ex = @macroexpand @struct_macro_51899() + const_field, const_field_with_type, + atomic_field, atomic_field_with_type = filter(x -> isa(x, Expr), ex.args[end].args[end].args) + @test Meta.isexpr(const_field, :const) + @test const_field.args[1] === :const_field + + @test Meta.isexpr(const_field_with_type, :const) + @test Meta.isexpr(const_field_with_type.args[1], :(::)) + @test const_field_with_type.args[1].args[1] === :const_field_with_type + @test const_field_with_type.args[1].args[2] == GlobalRef(@__MODULE__, :Int) + + @test Meta.isexpr(atomic_field, :atomic) + @test atomic_field.args[1] === :atomic_field + + @test Meta.isexpr(atomic_field_with_type, :atomic) + @test atomic_field_with_type.args[1].args[1] === :atomic_field_with_type + @test atomic_field_with_type.args[1].args[2] == GlobalRef(@__MODULE__, :Int) +end + # issue #25955 macro noeffect25955(e) return e From ace3cb049638ced4cf5d5c6c49af86f191f200fc Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 1 Nov 2023 17:13:52 +0100 Subject: [PATCH 2/2] fix reescape and propagate escape --- src/macroexpand.scm | 6 +++--- test/syntax.jl | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/macroexpand.scm b/src/macroexpand.scm index e70bd24289361..6e390a6c24cf2 100644 --- a/src/macroexpand.scm +++ b/src/macroexpand.scm @@ -340,8 +340,8 @@ (define (reescape ux x) (if (and (pair? x) (eq? (car x) 'escape)) - (reescape '(escape ,ux) (cadr x))) - ux) + (reescape `(escape ,ux) (cadr x)) + ux)) ;; type has special behavior: identifiers inside are ;; field names, not expressions. @@ -353,7 +353,7 @@ `(|::| ,(unescape (cadr ux)) ,(resolve-expansion-vars- (reescape (caddr ux) x) env m parent-scope inarg))) ((and (pair? ux) (memq (car ux) '(const atomic))) - `(,(car ux) ,(resolve-struct-field-expansion (cadr ux) env m parent-scope inarg))) + `(,(car ux) ,(resolve-struct-field-expansion (reescape (cadr ux) x) env m parent-scope inarg))) (else (resolve-expansion-vars-with-new-env x env m parent-scope inarg))))) diff --git a/test/syntax.jl b/test/syntax.jl index bc8418dadb072..97cb5fb8513f5 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -1789,6 +1789,7 @@ macro struct_macro_51899() mutable struct Struct51899 const const_field const const_field_with_type::Int + $(esc(Expr(:const, :(escaped_const_field::MyType)))) @atomic atomic_field @atomic atomic_field_with_type::Int end @@ -1796,7 +1797,7 @@ macro struct_macro_51899() end let ex = @macroexpand @struct_macro_51899() - const_field, const_field_with_type, + const_field, const_field_with_type, escaped_const_field, atomic_field, atomic_field_with_type = filter(x -> isa(x, Expr), ex.args[end].args[end].args) @test Meta.isexpr(const_field, :const) @test const_field.args[1] === :const_field @@ -1806,6 +1807,11 @@ let ex = @macroexpand @struct_macro_51899() @test const_field_with_type.args[1].args[1] === :const_field_with_type @test const_field_with_type.args[1].args[2] == GlobalRef(@__MODULE__, :Int) + @test Meta.isexpr(escaped_const_field, :const) + @test Meta.isexpr(const_field_with_type.args[1], :(::)) + @test escaped_const_field.args[1].args[1] === :escaped_const_field + @test escaped_const_field.args[1].args[2] === :MyType + @test Meta.isexpr(atomic_field, :atomic) @test atomic_field.args[1] === :atomic_field