From 9932de3934bc77aa03d3e1bfc609622c2f4e3802 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Fri, 28 Mar 2025 08:28:10 -0700 Subject: [PATCH 01/35] Update CodeInfo struct and handling Co-authored-by: Claire Foster --- src/eval.jl | 39 +++++++++++++++++++++++++++++++++------ src/linear_ir.jl | 2 +- test/misc.jl | 8 ++++++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/eval.jl b/src/eval.jl index eb4f2806..a130282a 100644 --- a/src/eval.jl +++ b/src/eval.jl @@ -12,6 +12,18 @@ function macroexpand(mod::Module, ex) ex1 end +function codeinfo_has_image_globalref(@nospecialize(e)) + if e isa GlobalRef + return 0x00 !== @ccall jl_object_in_image(e.mod::Any)::UInt8 + elseif e isa Core.CodeInfo + return any(codeinfo_has_image_globalref, e.code) + elseif e isa Expr + return any(codeinfo_has_image_globalref, e.args) + else + return false + end +end + _CodeInfo_need_ver = v"1.12.0-DEV.512" if VERSION < _CodeInfo_need_ver function _CodeInfo(args...) @@ -20,19 +32,29 @@ if VERSION < _CodeInfo_need_ver else # debuginfo changed completely as of https://github.com/JuliaLang/julia/pull/52415 # nargs / isva was added as of https://github.com/JuliaLang/julia/pull/54341 + # field rettype added in https://github.com/JuliaLang/julia/pull/54655 + # field has_image_globalref added in https://github.com/JuliaLang/julia/pull/57433 # CodeInfo constructor. TODO: Should be in Core let fns = fieldnames(Core.CodeInfo) fts = fieldtypes(Core.CodeInfo) conversions = [:(convert($t, $n)) for (t,n) in zip(fts, fns)] - expected_fns = (:code, :debuginfo, :ssavaluetypes, :ssaflags, :slotnames, :slotflags, :slottypes, :parent, :method_for_inference_limit_heuristics, :edges, :min_world, :max_world, :nargs, :propagate_inbounds, :has_fcall, :nospecializeinfer, :isva, :inlining, :constprop, :purity, :inlining_cost) - expected_fts = (Vector{Any}, Core.DebugInfo, Any, Vector{UInt32}, Vector{Symbol}, Vector{UInt8}, Any, Any, Any, Any, UInt64, UInt64, UInt64, Bool, Bool, Bool, Bool, UInt8, UInt8, UInt16, UInt16) + expected_fns = (:code, :debuginfo, :ssavaluetypes, :ssaflags, :slotnames, :slotflags, :slottypes, :rettype, :parent, :edges, :min_world, :max_world, :method_for_inference_limit_heuristics, :nargs, :propagate_inbounds, :has_fcall, :has_image_globalref, :nospecializeinfer, :isva, :inlining, :constprop, :purity, :inlining_cost) + expected_fts = (Vector{Any}, Core.DebugInfo, Any, Vector{UInt32}, Vector{Symbol}, Vector{UInt8}, Any, Any, Any, Any, UInt64, UInt64, Any, UInt64, Bool, Bool, Bool, Bool, Bool, UInt8, UInt8, UInt16, UInt16) - code = if fns != expected_fns || fts != expected_fts + code = if fns != expected_fns + unexpected_fns = collect(setdiff(Set(fns), Set(expected_fns))) + missing_fns = collect(setdiff(Set(expected_fns), Set(fns))) :(function _CodeInfo(args...) - error("Unrecognized CodeInfo layout: Maybe version $VERSION is to new for this version of JuliaLowering?") - end) + error("Unrecognized CodeInfo fields: Maybe version $VERSION is too new for this version of JuliaLowering?" + * isempty(unexpected_fns) ? "" : "\nUnexpected fields found: $($unexpected_fns)" + * isempty(missing_fns) ? "" : "\nMissing fields: $($missing_fns)") + end) + elseif fts != expected_fts + :(function _CodeInfo(args...) + error("Unrecognized CodeInfo field types: Maybe version $VERSION is too new for this version of JuliaLowering?") + end) else :(function _CodeInfo($(fns...)) $(Expr(:new, :(Core.CodeInfo), conversions...)) @@ -142,6 +164,8 @@ function to_code_info(ex, mod, funcname, slots) debuginfo = finish_ir_debug_info!(current_codelocs_stack) + has_image_globalref = any(codeinfo_has_image_globalref, stmts) + # TODO: Set ssaflags based on call site annotations: # - @inbounds annotations # - call site @inline / @noinline @@ -172,6 +196,7 @@ function to_code_info(ex, mod, funcname, slots) max_world = typemax(Csize_t) isva = false inlining_cost = 0xffff + rettype = Any _CodeInfo( stmts, @@ -181,14 +206,16 @@ function to_code_info(ex, mod, funcname, slots) slotnames, slotflags, slottypes, + rettype, parent, - method_for_inference_limit_heuristics, edges, min_world, max_world, + method_for_inference_limit_heuristics, nargs, propagate_inbounds, has_fcall, + has_image_globalref, nospecializeinfer, isva, inlining, diff --git a/src/linear_ir.jl b/src/linear_ir.jl index 0bb91f97..63fca9bf 100644 --- a/src/linear_ir.jl +++ b/src/linear_ir.jl @@ -69,7 +69,7 @@ end Context for creating linear IR. One of these is created per lambda expression to flatten the body down to -a sequence of statements (linear IR). +a sequence of statements (linear IR), which eventually becomes one CodeInfo. """ struct LinearIRContext{GraphType} <: AbstractLoweringContext graph::GraphType diff --git a/test/misc.jl b/test/misc.jl index 90bc32cc..25b31256 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -46,4 +46,12 @@ cf_float = JuliaLowering.include_string(test_mod, """ """) @test @ccall($cf_float(2::Float64, 3::Float64)::Float64) == 32.0 +@testset "CodeInfo: has_image_globalref" begin + elower(s) = JuliaLowering.to_lowered_expr( + test_mod, JuliaLowering.lower( + test_mod, parsestmt(JuliaLowering.SyntaxTree, s))) + @test elower("function foo end").args[1].has_image_globalref === false + @test elower("Base.push!([], 1)").args[1].has_image_globalref === true +end + end From 375f47451cece5cc9be8fc0e03ee90f1618d0013 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Mon, 31 Mar 2025 10:48:19 -0700 Subject: [PATCH 02/35] Don't produce raw symbol from globalref This used to implicitly refer to a module-level name, but lowering is now expected to wrap it in a `globalref`. Part of JuliaLang/julia#54772 --- src/eval.jl | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/eval.jl b/src/eval.jl index a130282a..a80e97bf 100644 --- a/src/eval.jl +++ b/src/eval.jl @@ -240,12 +240,7 @@ function to_lowered_expr(mod, ex, ssa_offset=0) elseif k == K"top" GlobalRef(Base, Symbol(ex.name_val)) elseif k == K"globalref" - if mod === ex.mod - # Implicitly refers to name in parent module. - Symbol(ex.name_val) - else - GlobalRef(ex.mod, Symbol(ex.name_val)) - end + GlobalRef(ex.mod, Symbol(ex.name_val)) elseif k == K"Identifier" # Implicitly refers to name in parent module # TODO: Should we even have plain identifiers at this point or should From 0e949783a6ef98f2d3d64cca1070b90a49dbd62d Mon Sep 17 00:00:00 2001 From: Em Chu Date: Tue, 1 Apr 2025 11:02:53 -0700 Subject: [PATCH 03/35] Updates to const and global lowering; add K"constdecl"; omit `wrap` JuliaLang/julia#54773, JuliaLang/julia#56713, JuliaLang/julia#57470. Some changes omitted from `expand-decls` and `expand-assignment`. Note that the two-argument IR "const" is K"constdecl", whereas the one-argument K"const" only appears in the AST. Also note that the `wrap` parameter is omitted throughout assignment desugaring. As far as I'm aware, all this plumbing was just to support `const a,b,c = 1,2,3` having `b` and `c` inherit the `const`. TODO: find a better way of doing the same thing (a ScopedValue might be a clean solution; we currently throw an error). The check for `let; const x = 1; end`, (which should throw) is in scope analysis (lisp has it in `compile`). Co-authored-by: Claire Foster --- src/closure_conversion.jl | 8 +-- src/desugaring.jl | 122 +++++++++++++++++++++++++++++++------- src/eval.jl | 3 +- src/kinds.jl | 8 ++- src/linear_ir.jl | 44 +++++++++++--- src/scope_analysis.jl | 17 ++++-- 6 files changed, 161 insertions(+), 41 deletions(-) diff --git a/src/closure_conversion.jl b/src/closure_conversion.jl index 211d6922..547cdf80 100644 --- a/src/closure_conversion.jl +++ b/src/closure_conversion.jl @@ -344,11 +344,11 @@ function _convert_closures(ctx::ClosureConversionCtx, ex) @assert kind(ex[1]) == K"BindingId" binfo = lookup_binding(ctx, ex[1]) if binfo.kind == :global - @ast ctx ex [K"call" - "set_binding_type!"::K"core" - binfo.mod::K"Value" - binfo.name::K"Symbol" + @ast ctx ex [ + K"globaldecl" + ex[1] _convert_closures(ctx, ex[2]) + # TODO (null)? ] else makeleaf(ctx, ex, K"TOMBSTONE") diff --git a/src/desugaring.jl b/src/desugaring.jl index b45603e5..0bcec66c 100644 --- a/src/desugaring.jl +++ b/src/desugaring.jl @@ -1165,16 +1165,21 @@ end # Expand assignments # Expand UnionAll definitions, eg `X{T} = Y{T,T}` -function expand_unionall_def(ctx, srcref, lhs, rhs) +function expand_unionall_def(ctx, srcref, lhs, rhs, is_const=true) if numchildren(lhs) <= 1 throw(LoweringError(lhs, "empty type parameter list in type alias")) end name = lhs[1] - @ast ctx srcref [K"block" - [K"const_if_global" name] - unionall_type := expand_forms_2(ctx, [K"where" rhs lhs[2:end]...]) - expand_forms_2(ctx, [K"=" name unionall_type]) - ] + rr = ssavar(ctx, srcref) + expand_forms_2( + ctx, + @ast ctx srcref [ + K"block" + [K"=" rr [K"where" rhs lhs[2:end]...]] + [is_const ? K"constdecl" : K"assign_const_if_global" name rr] + rr + ] + ) end # Expand general assignment syntax, including @@ -1184,13 +1189,13 @@ end # * Assignments to array elements # * Destructuring # * Typed variable declarations -function expand_assignment(ctx, ex) +function expand_assignment(ctx, ex, is_const=false) @chk numchildren(ex) == 2 lhs = ex[1] rhs = ex[2] kl = kind(lhs) if kl == K"curly" - expand_unionall_def(ctx, ex, lhs, rhs) + expand_unionall_def(ctx, ex, lhs, rhs, is_const) elseif kind(rhs) == K"=" # Expand chains of assignments # a = b = c ==> b=c; a=c @@ -1207,7 +1212,9 @@ function expand_assignment(ctx, ex) tmp_rhs = ssavar(ctx, rhs, "rhs") rr = tmp_rhs end - for i in 1:length(stmts) + # In const a = b = c, only a is const + stmts[1] = @ast ctx ex [(is_const ? K"constdecl" : K"=") stmts[1] rr] + for i in 2:length(stmts) stmts[i] = @ast ctx ex [K"=" stmts[i] rr] end if !isnothing(tmp_rhs) @@ -1220,9 +1227,20 @@ function expand_assignment(ctx, ex) ] ) elseif is_identifier_like(lhs) - sink_assignment(ctx, ex, lhs, expand_forms_2(ctx, rhs)) + if is_const + rr = ssavar(ctx, rhs) + @ast ctx ex [ + K"block" + sink_assignment(ctx, ex, rr, expand_forms_2(ctx, rhs)) + [K"constdecl" lhs rr] + [K"removable" rr] + ] + else + sink_assignment(ctx, ex, lhs, expand_forms_2(ctx, rhs)) + end elseif kl == K"." # a.b = rhs ==> setproperty!(a, :b, rhs) + @chk !is_const (ex, "cannot declare `.` form const") @chk numchildren(lhs) == 2 a = lhs[1] b = lhs[2] @@ -1250,16 +1268,24 @@ function expand_assignment(ctx, ex) end elseif kl == K"ref" # a[i1, i2] = rhs + @chk !is_const (ex, "cannot declare ref form const") expand_forms_2(ctx, expand_setindex(ctx, ex)) elseif kl == K"::" && numchildren(lhs) == 2 x = lhs[1] T = lhs[2] - res = if is_identifier_like(x) + res = if is_const + expand_forms_2(ctx, @ast ctx ex [ + K"const" + [K"=" + lhs[1] + convert_for_type_decl(ctx, ex, rhs, T, true) + ]]) + elseif is_identifier_like(x) # Identifer in lhs[1] is a variable type declaration, eg # x::T = rhs @ast ctx ex [K"block" [K"decl" lhs[1] lhs[2]] - [K"=" lhs[1] rhs] + is_const ? [K"const" [K"=" lhs[1] rhs]] : [K"=" lhs[1] rhs] ] else # Otherwise just a type assertion, eg @@ -1271,6 +1297,7 @@ function expand_assignment(ctx, ex) # needs to be detected somewhere but won't be detected here. Maybe # it shows that remove_argument_side_effects() is not the ideal # solution here? + # TODO: handle underscore? @ast ctx ex [K"block" stmts... [K"::" l1 lhs[2]] @@ -2097,9 +2124,8 @@ function strip_decls!(ctx, stmts, declkind, declkind2, declmeta, ex) end end -# local x, (y=2), z ==> local x; local y; y = 2; local z -# const x = 1 ==> const x; x = 1 -# global x::T = 1 ==> (block (global x) (decl x T) (x = 1)) +# local x, (y=2), z ==> local x; local z; y = 2 +# Note there are differences from lisp (evaluation order?) function expand_decls(ctx, ex) declkind = kind(ex) declmeta = get(ex, :meta, nothing) @@ -2129,6 +2155,58 @@ function expand_decls(ctx, ex) makenode(ctx, ex, K"block", stmts) end +# Return all the names that will be bound by the assignment LHS, including +# curlies and calls. +function lhs_bound_names(ex) + k = kind(ex) + if k == K"Placeholder" + [] + elseif is_identifier_like(ex) + [ex] + elseif k in KSet"call curly where ::" + lhs_bound_names(ex[1]) + elseif k in KSet"tuple parameters" + vcat(map(lhs_bound_names, children(ex))...) + else + [] + end +end + +function expand_const_decl(ctx, ex) + function check_assignment(asgn) + @chk (kind(asgn) == K"=") (ex, "expected assignment after `const`") + end + + k = kind(ex[1]) + if numchildren(ex) == 2 + @ast ctx ex [ + K"constdecl" + ex[1] + expand_forms_2(ctx, ex[2]) + ] + elseif k == K"global" + asgn = ex[1][1] + check_assignment(asgn) + globals = map(lhs_bound_names(asgn[1])) do x + @ast ctx ex [K"global" x] + end + @ast ctx ex [ + K"block" + globals... + expand_assignment(ctx, ex[1], true) + ] + elseif k == K"=" + if numchildren(ex[1]) >= 1 && kind(ex[1][1]) == K"tuple" + throw(LoweringError(ex[1][1], "unsupported `const` tuple")) + end + expand_assignment(ctx, ex[1], true) + elseif k == K"local" + throw(LoweringError(ex, "unsupported `const local` declaration")) + else + throw(LoweringError(ex, "expected assignment after `const`")) + end +end + #------------------------------------------------------------------------------- # Expansion of function definitions @@ -3318,14 +3396,13 @@ function expand_abstract_or_primitive_type(ctx, ex) ] [K"assert" "toplevel_only"::K"Symbol" [K"inert" ex] ] [K"global" name] - [K"const" name] [K"if" [K"&&" [K"isdefined" name] [K"call" "_equiv_typedef"::K"core" name newtype_var] ] nothing_(ctx, ex) - [K"=" name newtype_var] + [K"constdecl" name newtype_var] ] nothing_(ctx, ex) ] @@ -3827,9 +3904,10 @@ function expand_struct_def(ctx, ex, docs) @ast ctx ex [K"block" [K"assert" "toplevel_only"::K"Symbol" [K"inert" ex] ] [K"scope_block"(scope_type=:hard) + # Needed for later constdecl to work, though plain global form may be removed soon. + [K"global" global_struct_name] [K"block" [K"global" global_struct_name] - [K"const" global_struct_name] [K"local" struct_name] [K"always_defined" struct_name] typevar_stmts... @@ -3868,9 +3946,9 @@ function expand_struct_def(ctx, ex, docs) end ] # Otherwise do an assignment to trigger an error - [K"=" global_struct_name struct_name] + [K"const" global_struct_name struct_name] ] - [K"=" global_struct_name struct_name] + [K"const" global_struct_name struct_name] ] [K"call"(type_body) "_typebody!"::K"core" @@ -4271,7 +4349,9 @@ function expand_forms_2(ctx::DesugaringContext, ex::SyntaxTree, docs=nothing) ] elseif k == K"let" expand_forms_2(ctx, expand_let(ctx, ex)) - elseif k == K"local" || k == K"global" || k == K"const" + elseif k == K"const" + expand_const_decl(ctx, ex) + elseif k == K"local" || k == K"global" if numchildren(ex) == 1 && kind(ex[1]) == K"Identifier" # Don't recurse when already simplified - `local x`, etc ex diff --git a/src/eval.jl b/src/eval.jl index a80e97bf..d72b65c9 100644 --- a/src/eval.jl +++ b/src/eval.jl @@ -310,9 +310,10 @@ function to_lowered_expr(mod, ex, ssa_offset=0) k == K"splatnew" ? :splatnew : k == K"=" ? :(=) : k == K"global" ? :global : - k == K"const" ? :const : + k == K"constdecl" ? :const : k == K"leave" ? :leave : k == K"isdefined" ? :isdefined : + k == K"globaldecl" ? :globaldecl : k == K"pop_exception" ? :pop_exception : k == K"captured_local" ? :captured_local : k == K"gc_preserve_begin" ? :gc_preserve_begin : diff --git a/src/kinds.jl b/src/kinds.jl index 6a1a4ecc..03c81dcb 100644 --- a/src/kinds.jl +++ b/src/kinds.jl @@ -96,7 +96,7 @@ function _register_kinds() "_opaque_closure" # The enclosed statements must be executed at top level "toplevel_butfirst" - "const_if_global" + "assign_const_if_global" "moved_local" "label" "trycatchelse" @@ -121,8 +121,12 @@ function _register_kinds() "slot" # Static parameter to a `CodeInfo` code object ("type parameters" to methods) "static_parameter" - # Reference to a global variable within a module + # References/declares a global variable within a module "globalref" + "globaldecl" + # Two-argument constant declaration and assignment. + # Translated to :const in the IR for now (we use K"const" already in parsing). + "constdecl" # Unconditional goto "goto" # Conditional goto diff --git a/src/linear_ir.jl b/src/linear_ir.jl index 63fca9bf..c1456bed 100644 --- a/src/linear_ir.jl +++ b/src/linear_ir.jl @@ -334,18 +334,35 @@ function emit_break(ctx, ex) emit_jump(ctx, ex, target) end -function emit_assignment(ctx, srcref, lhs, rhs) +# `op` may also be K"constdecl" +function emit_assignment_or_setglobal(ctx, srcref, lhs, rhs, op=K"=") + # (const (globalref _ _) _) does not use setglobal! + binfo = lookup_binding(ctx, lhs.var_id) + if binfo.kind == :global && op == K"=" + emit(ctx, @ast ctx srcref [ + K"call" + "setglobal!"::K"top" + binfo.mod::K"Value" + binfo.name::K"Symbol" + rhs + ]) + else + emit(ctx, srcref, op, lhs, rhs) + end +end + +function emit_assignment(ctx, srcref, lhs, rhs, op=K"=") if !isnothing(rhs) if is_valid_ir_rvalue(ctx, lhs, rhs) - emit(ctx, srcref, K"=", lhs, rhs) + emit_assignment_or_setglobal(ctx, srcref, lhs, rhs, op) else r = emit_assign_tmp(ctx, rhs) - emit(ctx, srcref, K"=", lhs, r) + emit_assignment_or_setglobal(ctx, srcref, lhs, r, op) end else # in unreachable code (such as after return); still emit the assignment # so that the structure of those uses is preserved - emit(ctx, @ast ctx srcref [K"=" lhs "nothing"::K"core"]) + emit_assignment_or_setglobal(ctx, srcref, lhs, @ast ctx srcref "nothing"::K"core", op) nothing end end @@ -640,7 +657,7 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos) emit(ctx, callex) nothing end - elseif k == K"=" + elseif k == K"=" || k == K"constdecl" lhs = ex[1] if kind(lhs) == K"Placeholder" compile(ctx, ex[2], needs_value, in_tail_pos) @@ -649,14 +666,14 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos) # TODO look up arg-map for renaming if lhs was reassigned if needs_value && !isnothing(rhs) r = emit_assign_tmp(ctx, rhs) - emit(ctx, ex, K"=", lhs, r) + emit_assignment_or_setglobal(ctx, ex, lhs, r, k) if in_tail_pos emit_return(ctx, ex, r) else r end else - emit_assignment(ctx, ex, lhs, rhs) + emit_assignment(ctx, ex, lhs, rhs, k) end end elseif k == K"block" || k == K"scope_block" @@ -811,7 +828,7 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos) end elseif k == K"gc_preserve_begin" makenode(ctx, ex, k, compile_args(ctx, children(ex))) - elseif k == K"gc_preserve_end" || k == K"global" || k == K"const" + elseif k == K"gc_preserve_end" || k == K"global" if needs_value throw(LoweringError(ex, "misplaced kind $k in value position")) end @@ -862,6 +879,17 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos) # TODO: also exclude deleted vars emit(ctx, ex) end + elseif k == K"globaldecl" + if needs_value + throw(LoweringError(ex, "misplaced global declaration")) + end + if numchildren(ex) == 1 || is_identifier_like(ex[2]) + emit(ctx, ex) + else + rr = ssavar(ctx, ex[2]) + emit(ctx, @ast ctx ex [K"=" rr ex[2]]) + emit(ctx, @ast ctx ex [K"globaldecl" ex[1] rr]) + end else throw(LoweringError(ex, "Invalid syntax; $(repr(k))")) end diff --git a/src/scope_analysis.jl b/src/scope_analysis.jl index 343b5c6b..59314149 100644 --- a/src/scope_analysis.jl +++ b/src/scope_analysis.jl @@ -44,7 +44,11 @@ function _find_scope_vars!(ctx, assignments, locals, destructured_args, globals, end elseif k == K"global" _insert_if_not_present!(globals, NameKey(ex[1]), ex) - elseif k == K"=" + elseif k == K"assign_const_if_global" + # like v = val, except that if `v` turns out global(either implicitly or + # by explicit `global`), it gains an implicit `const` + _insert_if_not_present!(assignments, NameKey(ex[1]), ex) + elseif k == K"=" || k == K"constdecl" v = decl_var(ex[1]) if !(kind(v) in KSet"BindingId globalref Placeholder") _insert_if_not_present!(assignments, NameKey(v), v) @@ -561,10 +565,13 @@ function _resolve_scopes(ctx, ex::SyntaxTree) end end resolved - elseif k == K"const_if_global" + elseif k == K"assign_const_if_global" id = _resolve_scopes(ctx, ex[1]) - if lookup_binding(ctx, id).kind == :global - @ast ctx ex [K"const" id] + bk = lookup_binding(ctx, id).kind + if bk == :local && numchildren(ex) != 1 + @ast ctx ex _resolve_scopes(ctx, [K"=" children(ex)...]) + elseif bk != :local # TODO: should this be == :global? + @ast ctx ex _resolve_scopes(ctx, [K"constdecl" children(ex)...]) else makeleaf(ctx, ex, K"TOMBSTONE") end @@ -677,7 +684,7 @@ function analyze_variables!(ctx, ex) if kind(ex[1]) != K"BindingId" || lookup_binding(ctx, ex[1]).kind !== :local analyze_variables!(ctx, ex[1]) end - elseif k == K"const" + elseif k == K"constdecl" id = ex[1] if lookup_binding(ctx, id).kind == :local throw(LoweringError(ex, "unsupported `const` declaration on local variable")) From b1c0b09c91c6972cce4c797d999d29bc2f82265b Mon Sep 17 00:00:00 2001 From: Em Chu Date: Tue, 1 Apr 2025 11:07:09 -0700 Subject: [PATCH 04/35] Add `isdefinedglobal` builtin JuliaLang/julia#54999, JuliaLang/julia#56985 --- src/closure_conversion.jl | 7 +++++++ src/desugaring.jl | 11 +++++++++-- test/scopes_ir.jl | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/closure_conversion.jl b/src/closure_conversion.jl index 547cdf80..fa40ff20 100644 --- a/src/closure_conversion.jl +++ b/src/closure_conversion.jl @@ -337,6 +337,13 @@ function _convert_closures(ctx::ClosureConversionCtx, ex) elseif binfo.is_always_defined || is_self_captured(ctx, var) # Captured but unboxed vars are always defined @ast ctx ex true::K"Bool" + elseif binfo.kind == :global + # Normal isdefined won't work for globals (#56985) + @ast ctx ex [K"call" + "isdefinedglobal"::K"core" + ctx.mod::K"Value" + binfo.name::K"Symbol" + false::K"Bool"] else ex end diff --git a/src/desugaring.jl b/src/desugaring.jl index 0bcec66c..4bedcf1a 100644 --- a/src/desugaring.jl +++ b/src/desugaring.jl @@ -3398,7 +3398,11 @@ function expand_abstract_or_primitive_type(ctx, ex) [K"global" name] [K"if" [K"&&" - [K"isdefined" name] + [K"call" + "isdefinedglobal"::K"core" + ctx.mod::K"Value" + name=>K"Symbol" + false::K"Bool"] [K"call" "_equiv_typedef"::K"core" name newtype_var] ] nothing_(ctx, ex) @@ -3927,7 +3931,10 @@ function expand_struct_def(ctx, ex, docs) [K"=" struct_name newtype_var] [K"call"(supertype) "_setsuper!"::K"core" newtype_var supertype] [K"if" - [K"isdefined" global_struct_name] + [K"call" "isdefinedglobal"::K"core" + ctx.mod::K"Value" + struct_name=>K"Symbol" + false::K"Bool"] [K"if" [K"call" "_equiv_typedef"::K"core" global_struct_name newtype_var] [K"block" diff --git a/test/scopes_ir.jl b/test/scopes_ir.jl index c0013a39..4434f6f7 100644 --- a/test/scopes_ir.jl +++ b/test/scopes_ir.jl @@ -418,6 +418,6 @@ end #--------------------- 1 1 2 (= slot₁/x %₁) -3 (isdefined TestMod.y) +3 (call core.isdefinedglobal TestMod :y false) 4 (return %₃) From 7d2efcad7681327ac463882da1de6c7942d2e38f Mon Sep 17 00:00:00 2001 From: Em Chu Date: Tue, 1 Apr 2025 11:09:09 -0700 Subject: [PATCH 05/35] :global no longer valid_ir_argument; rm `is_defined_nothrow_global` JuliaLang/julia#56746. Also call :slot and :static_parameter valid (for now) --- src/linear_ir.jl | 13 ++----------- src/runtime.jl | 10 ---------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/src/linear_ir.jl b/src/linear_ir.jl index c1456bed..dafd0e95 100644 --- a/src/linear_ir.jl +++ b/src/linear_ir.jl @@ -3,7 +3,7 @@ function is_valid_ir_argument(ctx, ex) k = kind(ex) - if is_simple_atom(ctx, ex) || k == K"inert" || k == K"top" || k == K"core" + if is_simple_atom(ctx, ex) || k in KSet"inert top core quote" true elseif k == K"BindingId" binfo = lookup_binding(ctx, ex) @@ -11,16 +11,7 @@ function is_valid_ir_argument(ctx, ex) # TODO: Can we allow bk == :local || bk == :argument || bk == :static_parameter ??? # Why does flisp seem to allow (slot) and (static_parameter), but these # aren't yet converted to by existing lowering?? - if bk == :global - # Globals are nothrow when they are defined - we assume a previously - # defined global can never be set to undefined. (TODO: This could be - # broken when precompiling a module `B` in the presence of a badly - # behaved module `A`, which inconsistently defines globals during - # `A.__init__()`??) - is_defined_nothrow_global(binfo.mod, Symbol(binfo.name)) - else - false - end + (bk == :slot || bk == :static_parameter) else false end diff --git a/src/runtime.jl b/src/runtime.jl index a3d9c2ce..a0409a35 100644 --- a/src/runtime.jl +++ b/src/runtime.jl @@ -375,16 +375,6 @@ function is_defined_and_owned_global(mod, name) !isnothing(b) && isdefined(b, :owner) && b.owner === b end -# Return true if `name` is defined in `mod`, the sense that accessing it is nothrow. -# Has no side effects, unlike isdefined() -# -# (This should do what fl_nothrow_julia_global does for flisp lowering) -function is_defined_nothrow_global(mod, name) - b = _get_module_binding(mod, name) - !isnothing(b) && isdefined(b, :owner) || return false - isdefined(b.owner, :value) -end - # "Reserve" a binding: create the binding if it doesn't exist but do not assign # to it. function reserve_module_binding(mod, name) From 950b87c414b596b23f0df3593523418ec18ba879 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Thu, 17 Apr 2025 14:38:31 -0700 Subject: [PATCH 06/35] Fix `is_defined_and_owned_global` (Core.Binding changes) Adapt to bpart changes in JuliaLang/julia#54788 --- src/runtime.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/runtime.jl b/src/runtime.jl index a0409a35..26a2730f 100644 --- a/src/runtime.jl +++ b/src/runtime.jl @@ -371,8 +371,7 @@ end # # (This should do what fl_defined_julia_global does for flisp lowering) function is_defined_and_owned_global(mod, name) - b = _get_module_binding(mod, name) - !isnothing(b) && isdefined(b, :owner) && b.owner === b + Base.binding_kind(mod, name) === Base.PARTITION_KIND_GLOBAL end # "Reserve" a binding: create the binding if it doesn't exist but do not assign From 7194d9bd94d49a0e13d52f3d325d6ece66a652ce Mon Sep 17 00:00:00 2001 From: Em Chu Date: Tue, 1 Apr 2025 11:30:31 -0700 Subject: [PATCH 07/35] Struct desugaring: "Undo decision to publish incomplete types..." JuliaLang/julia#56497; Add self-referencing struct shim I have doubts about how long this solution will stay in the base repository, and how complete it is (doesn't seem to work with M1.M2.S), but we are testing for it here. Also change the expected value of a test changed in the same PR. --- src/desugaring.jl | 27 +++++++++++++++++++++++---- test/typedefs.jl | 2 +- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/desugaring.jl b/src/desugaring.jl index 4bedcf1a..33601bdc 100644 --- a/src/desugaring.jl +++ b/src/desugaring.jl @@ -3825,6 +3825,24 @@ function _constructor_min_initalized(ex::SyntaxTree) end end +# Let S be a struct we're defining in module M. Below is a hack to allow its +# field types to refer to S as M.S. See #56497. +function insert_struct_shim(ctx, fieldtypes, name) + function replace_type(ex) + if kind(ex) == K"." && + numchildren(ex) == 2 && + kind(ex[2]) == K"Symbol" && + ex[2].name_val == name.name_val + @ast ctx ex [K"call" "struct_name_shim"::K"core" ex[1] ex[2] ctx.mod::K"Value" name] + elseif numchildren(ex) > 0 + @ast ctx ex [ex.kind map(replace_type, children(ex))...] + else + ex + end + end + map(replace_type, fieldtypes) +end + function expand_struct_def(ctx, ex, docs) @chk numchildren(ex) == 2 type_sig = ex[1] @@ -3952,16 +3970,17 @@ function expand_struct_def(ctx, ex, docs) ] end ] - # Otherwise do an assignment to trigger an error - [K"const" global_struct_name struct_name] ] - [K"const" global_struct_name struct_name] ] [K"call"(type_body) "_typebody!"::K"core" struct_name - [K"call" "svec"::K"core" field_types...] + [K"call" "svec"::K"core" insert_struct_shim(ctx, field_types, struct_name)...] ] + [K"constdecl" + global_struct_name + newtype_var + ] # Default constructors if isempty(inner_defs) default_inner_constructors(ctx, ex, global_struct_name, diff --git a/test/typedefs.jl b/test/typedefs.jl index d2f0594b..4bc91fb9 100644 --- a/test/typedefs.jl +++ b/test/typedefs.jl @@ -251,7 +251,7 @@ end """) @test fieldtypes(test_mod.M36104.T36104) == (Vector{test_mod.M36104.T36104},) @test_throws ErrorException("expected") JuliaLowering.include_string(test_mod, """struct X36104; x::error("expected"); end""") -@test isdefined(test_mod, :X36104) +@test !isdefined(test_mod, :X36104) JuliaLowering.include_string(test_mod, "struct X36104; x::Int; end") @test fieldtypes(test_mod.X36104) == (Int,) JuliaLowering.include_string(test_mod, "primitive type P36104 8 end") From 32aab4f2e055b4e29ff1272b834673f9cad19aff Mon Sep 17 00:00:00 2001 From: Em Chu Date: Wed, 2 Apr 2025 08:32:34 -0700 Subject: [PATCH 08/35] Emit `latestworld` world age increments For method defs, `latestworld` is produced in desugaring rather than closure conversion for now (our closure conversion doesn't seem to cover the same cases as lisp lowering yet). Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299. Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing min_world for global variable definitions) since the lowering changes from those appear to be amendments to the changes above (missing world age increments). Co-authored-by: Claire Foster --- src/closure_conversion.jl | 3 ++- src/desugaring.jl | 21 +++++++++++++++++++++ src/eval.jl | 1 + src/kinds.jl | 4 ++++ src/linear_ir.jl | 14 +++++++++++++- src/syntax_graph.jl | 1 + 6 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/closure_conversion.jl b/src/closure_conversion.jl index fa40ff20..808d2d92 100644 --- a/src/closure_conversion.jl +++ b/src/closure_conversion.jl @@ -355,7 +355,6 @@ function _convert_closures(ctx::ClosureConversionCtx, ex) K"globaldecl" ex[1] _convert_closures(ctx, ex[2]) - # TODO (null)? ] else makeleaf(ctx, ex, K"TOMBSTONE") @@ -389,6 +388,7 @@ function _convert_closures(ctx::ClosureConversionCtx, ex) type_for_closure(ctx, ex, name_str, field_syms, field_is_box) if !ctx.is_toplevel_seq_point push!(ctx.toplevel_stmts, closure_type_def) + push!(ctx.toplevel_stmts, @ast ctx ex [K"latestworld_if_toplevel"]) closure_type_def = nothing end closure_info = ClosureInfo(closure_type_, field_syms, field_inds) @@ -413,6 +413,7 @@ function _convert_closures(ctx::ClosureConversionCtx, ex) end @ast ctx ex [K"block" closure_type_def + [K"latestworld_if_toplevel"] closure_type := if isempty(type_params) closure_type_ else diff --git a/src/desugaring.jl b/src/desugaring.jl index 33601bdc..0d61b68a 100644 --- a/src/desugaring.jl +++ b/src/desugaring.jl @@ -1177,6 +1177,7 @@ function expand_unionall_def(ctx, srcref, lhs, rhs, is_const=true) K"block" [K"=" rr [K"where" rhs lhs[2:end]...]] [is_const ? K"constdecl" : K"assign_const_if_global" name rr] + [K"latestworld_if_toplevel"] rr ] ) @@ -1233,6 +1234,7 @@ function expand_assignment(ctx, ex, is_const=false) K"block" sink_assignment(ctx, ex, rr, expand_forms_2(ctx, rhs)) [K"constdecl" lhs rr] + [K"latestworld"] [K"removable" rr] ] else @@ -1849,6 +1851,17 @@ function expand_call(ctx, ex) expand_forms_2(ctx, farg) expand_forms_2(ctx, _wrap_unsplatted_args(ctx, ex, args))... ] + elseif kind(farg) == K"Identifier" && farg.name_val == "include" + # world age special case + r = ssavar(ctx, ex) + @ast ctx ex [K"block" + [K"=" r [K"call" + expand_forms_2(ctx, farg) + expand_forms_2(ctx, args)... + ]] + [K"latestworld_if_toplevel"] + r + ] else @ast ctx ex [K"call" expand_forms_2(ctx, farg) @@ -2321,6 +2334,7 @@ function method_def_expr(ctx, srcref, callex_srcref, method_table, ret_var # might be `nothing` and hence removed ] ] + [K"latestworld"] [K"removable" method_metadata] ] end @@ -2449,10 +2463,12 @@ function expand_function_generator(ctx, srcref, callex_srcref, func_name, func_n # Code generator definition gen_func_method_defs = @ast ctx srcref [K"block" [K"function_decl" gen_name] + [K"latestworld_if_toplevel"] [K"scope_block"(scope_type=:hard) [K"method_defs" gen_name [K"block" + [K"latestworld_if_toplevel"] method_def_expr(ctx, srcref, callex_srcref, nothing, SyntaxList(ctx), gen_arg_names, gen_arg_types, gen_body, nothing) ] @@ -2786,6 +2802,7 @@ function keyword_function_defs(ctx, srcref, callex_srcref, name_str, typevar_nam kw_func_method_defs = @ast ctx srcref [K"block" [K"function_decl" body_func_name] + [K"latestworld"] [K"scope_block"(scope_type=:hard) [K"method_defs" body_func_name @@ -2855,6 +2872,7 @@ function expand_function_def(ctx, ex, docs, rewrite_call=identity, rewrite_body= end return @ast ctx ex [K"block" [K"function_decl" name] + [K"latestworld"] name ] end @@ -3091,6 +3109,7 @@ function expand_function_def(ctx, ex, docs, rewrite_call=identity, rewrite_body= end gen_func_method_defs kw_func_method_defs + [K"latestworld_if_toplevel"] [K"scope_block"(scope_type=:hard) [K"method_defs" isnothing(bare_func_name) ? "nothing"::K"core" : bare_func_name @@ -3408,6 +3427,7 @@ function expand_abstract_or_primitive_type(ctx, ex) nothing_(ctx, ex) [K"constdecl" name newtype_var] ] + [K"latestworld"] nothing_(ctx, ex) ] end @@ -3981,6 +4001,7 @@ function expand_struct_def(ctx, ex, docs) global_struct_name newtype_var ] + [K"latestworld"] # Default constructors if isempty(inner_defs) default_inner_constructors(ctx, ex, global_struct_name, diff --git a/src/eval.jl b/src/eval.jl index d72b65c9..478e0de1 100644 --- a/src/eval.jl +++ b/src/eval.jl @@ -313,6 +313,7 @@ function to_lowered_expr(mod, ex, ssa_offset=0) k == K"constdecl" ? :const : k == K"leave" ? :leave : k == K"isdefined" ? :isdefined : + k == K"latestworld" ? :latestworld : k == K"globaldecl" ? :globaldecl : k == K"pop_exception" ? :pop_exception : k == K"captured_local" ? :captured_local : diff --git a/src/kinds.jl b/src/kinds.jl index 03c81dcb..0714f1d6 100644 --- a/src/kinds.jl +++ b/src/kinds.jl @@ -111,6 +111,8 @@ function _register_kinds() # A local variable captured into a global method. Contains the # `index` of the associated `Box` in the rewrite list. "captured_local" + # Causes the linearization pass to conditionally emit a world age increment + "latestworld_if_toplevel" "END_LOWERING_KINDS" # The following kinds are emitted by lowering and used in Julia's untyped IR @@ -147,6 +149,8 @@ function _register_kinds() "new_opaque_closure" # Wrapper for the lambda of around opaque closure methods "opaque_closure_method" + # World age increment + "latestworld" "END_IR_KINDS" ]) end diff --git a/src/linear_ir.jl b/src/linear_ir.jl index dafd0e95..0ac56ce4 100644 --- a/src/linear_ir.jl +++ b/src/linear_ir.jl @@ -819,12 +819,19 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos) end elseif k == K"gc_preserve_begin" makenode(ctx, ex, k, compile_args(ctx, children(ex))) - elseif k == K"gc_preserve_end" || k == K"global" + elseif k == K"gc_preserve_end" if needs_value throw(LoweringError(ex, "misplaced kind $k in value position")) end emit(ctx, ex) nothing + elseif k == K"global" + if needs_value + throw(LoweringError(ex, "misplaced kind $k in value position")) + end + emit(ctx, ex) + ctx.is_toplevel_thunk && emit(ctx, makenode(ctx, ex, K"latestworld")) + nothing elseif k == K"meta" emit(ctx, ex) if needs_value @@ -881,6 +888,11 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos) emit(ctx, @ast ctx ex [K"=" rr ex[2]]) emit(ctx, @ast ctx ex [K"globaldecl" ex[1] rr]) end + ctx.is_toplevel_thunk && emit(ctx, makenode(ctx, ex, K"latestworld")) + elseif k == K"latestworld" + emit(ctx, ex) + elseif k == K"latestworld_if_toplevel" + ctx.is_toplevel_thunk && emit(ctx, makeleaf(ctx, ex, K"latestworld")) else throw(LoweringError(ex, "Invalid syntax; $(repr(k))")) end diff --git a/src/syntax_graph.jl b/src/syntax_graph.jl index bdbf98e0..28af9cfb 100644 --- a/src/syntax_graph.jl +++ b/src/syntax_graph.jl @@ -431,6 +431,7 @@ function _value_string(ex) k == K"Symbol" ? ":$(ex.name_val)" : k == K"globalref" ? "$(ex.mod).$(ex.name_val)" : k == K"slot" ? "slot" : + k == K"latestworld" ? "(latestworld)" : k == K"static_parameter" ? "static_parameter" : k == K"symbolic_label" ? "label:$(ex.name_val)" : k == K"symbolic_goto" ? "goto:$(ex.name_val)" : From 1501b341bde5dd1e5931aa7293bd1dbaa9c703a5 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Fri, 4 Apr 2025 08:43:45 -0700 Subject: [PATCH 09/35] bpart changes: `Core._typebody!` signature `Core._typebody!` now takes a new "prev" argument, which we don't use yet here. Changes from JuliaLang/julia#57253 --- src/closure_conversion.jl | 1 + src/desugaring.jl | 6 ++++-- src/runtime.jl | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/closure_conversion.jl b/src/closure_conversion.jl index 808d2d92..cbcdf16b 100644 --- a/src/closure_conversion.jl +++ b/src/closure_conversion.jl @@ -147,6 +147,7 @@ function convert_global_assignment(ctx, ex, var, rhs0) end push!(stmts, @ast ctx ex [K"=" var rhs]) @ast ctx ex [K"block" + [K"globaldecl" var] stmts... rhs1 ] diff --git a/src/desugaring.jl b/src/desugaring.jl index 0d61b68a..4858a747 100644 --- a/src/desugaring.jl +++ b/src/desugaring.jl @@ -3410,7 +3410,7 @@ function expand_abstract_or_primitive_type(ctx, ex) ] [K"=" name newtype_var] [K"call" "_setsuper!"::K"core" newtype_var supertype] - [K"call" "_typebody!"::K"core" newtype_var] + [K"call" "_typebody!"::K"core" false::K"Bool" name] ] ] [K"assert" "toplevel_only"::K"Symbol" [K"inert" ex] ] @@ -3994,7 +3994,9 @@ function expand_struct_def(ctx, ex, docs) ] [K"call"(type_body) "_typebody!"::K"core" - struct_name + # TODO: if there is a previous compatible definition, re-use params. See #57253 + false::K"Bool" + newtype_var [K"call" "svec"::K"core" insert_struct_shim(ctx, field_types, struct_name)...] ] [K"constdecl" diff --git a/src/runtime.jl b/src/runtime.jl index 26a2730f..aa4a509b 100644 --- a/src/runtime.jl +++ b/src/runtime.jl @@ -130,7 +130,7 @@ function eval_closure_type(mod, closure_type_name, field_names, field_is_box) length(field_names)) Core._setsuper!(type, Core.Function) Base.eval(mod, :(const $closure_type_name = $type)) - Core._typebody!(type, Core.svec(field_types...)) + Core._typebody!(false, type, Core.svec(field_types...)) type end From e1d34440ad1e03b2e4bcbc36733d54ab7402f6bb Mon Sep 17 00:00:00 2001 From: Em Chu Date: Fri, 18 Apr 2025 09:11:58 -0700 Subject: [PATCH 10/35] bpart changes: struct desugaring Changes from JuliaLang/julia#57253 (bpart: Fully switch to partitioned semantics). This fixes one failing test and realigns struct desugaring to match lisp for now. Also changed: the expected result of redefining a primitive type (now allowed). --- src/desugaring.jl | 61 +++++++++++++++++++++++------------------------ test/typedefs.jl | 5 ++-- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/desugaring.jl b/src/desugaring.jl index 4858a747..4e4c1b9b 100644 --- a/src/desugaring.jl +++ b/src/desugaring.jl @@ -3883,6 +3883,9 @@ function expand_struct_def(ctx, ex, docs) min_initialized = minimum((_constructor_min_initalized(e) for e in inner_defs), init=length(field_names)) newtype_var = ssavar(ctx, ex, "struct_type") + hasprev = ssavar(ctx, ex, "hasprev") + prev = ssavar(ctx, ex, "prev") + newdef = ssavar(ctx, ex, "newdef") layer = new_scope_layer(ctx, struct_name) global_struct_name = adopt_scope(struct_name, layer) if !isempty(typevar_names) @@ -3949,7 +3952,6 @@ function expand_struct_def(ctx, ex, docs) # Needed for later constdecl to work, though plain global form may be removed soon. [K"global" global_struct_name] [K"block" - [K"global" global_struct_name] [K"local" struct_name] [K"always_defined" struct_name] typevar_stmts... @@ -3968,40 +3970,37 @@ function expand_struct_def(ctx, ex, docs) ] [K"=" struct_name newtype_var] [K"call"(supertype) "_setsuper!"::K"core" newtype_var supertype] - [K"if" - [K"call" "isdefinedglobal"::K"core" - ctx.mod::K"Value" - struct_name=>K"Symbol" - false::K"Bool"] - [K"if" - [K"call" "_equiv_typedef"::K"core" global_struct_name newtype_var] - [K"block" - # If this is compatible with an old definition, use - # the existing type object and throw away the new - # type - [K"=" struct_name global_struct_name] - if !isempty(typevar_names) - # And resassign the typevar_names - these may be - # referenced in the definition of the field - # types below - [K"=" - [K"tuple" typevar_names...] - prev_typevars - ] - end - ] + [K"=" hasprev + [K"&&" [K"call" "isdefinedglobal"::K"core" + ctx.mod::K"Value" + struct_name=>K"Symbol" + false::K"Bool"] + [K"call" "_equiv_typedef"::K"core" global_struct_name newtype_var] + ]] + [K"=" prev [K"if" hasprev global_struct_name false::K"Bool"]] + [K"if" hasprev + [K"block" + # if this is compatible with an old definition, use the old parameters, but the + # new object. This will fail to capture recursive cases, but the call to typebody! + # below is permitted to choose either type definition to put into the binding table + if !isempty(typevar_names) + # And resassign the typevar_names - these may be + # referenced in the definition of the field + # types below + [K"=" [K"tuple" typevar_names...] prev_typevars] + end ] ] - [K"call"(type_body) - "_typebody!"::K"core" - # TODO: if there is a previous compatible definition, re-use params. See #57253 - false::K"Bool" - newtype_var - [K"call" "svec"::K"core" insert_struct_shim(ctx, field_types, struct_name)...] - ] + [K"=" newdef + [K"call"(type_body) + "_typebody!"::K"core" + prev + newtype_var + [K"call" "svec"::K"core" insert_struct_shim(ctx, field_types, struct_name)...] + ]] [K"constdecl" global_struct_name - newtype_var + newdef ] [K"latestworld"] # Default constructors diff --git a/test/typedefs.jl b/test/typedefs.jl index 4bc91fb9..be509eeb 100644 --- a/test/typedefs.jl +++ b/test/typedefs.jl @@ -255,8 +255,9 @@ end JuliaLowering.include_string(test_mod, "struct X36104; x::Int; end") @test fieldtypes(test_mod.X36104) == (Int,) JuliaLowering.include_string(test_mod, "primitive type P36104 8 end") -@test_throws ErrorException("invalid redefinition of constant TestMod.P36104") #= - =# JuliaLowering.include_string(test_mod, "primitive type P36104 16 end") +JuliaLowering.include_string(test_mod, "const orig_P36104 = P36104") +JuliaLowering.include_string(test_mod, "primitive type P36104 16 end") +@test test_mod.P36104 !== test_mod.orig_P36104 # Struct with outer constructor where one typevar is constrained by the other # See https://github.com/JuliaLang/julia/issues/27269) From ed91f961d380b436aab0c2e6574460c3964690c0 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Fri, 4 Apr 2025 09:39:07 -0700 Subject: [PATCH 11/35] Additional argument in `new_opaque_closure` Fix segfaulting test. Thanks for the TODO --- src/eval.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/eval.jl b/src/eval.jl index 478e0de1..93e43ef2 100644 --- a/src/eval.jl +++ b/src/eval.jl @@ -290,8 +290,6 @@ function to_lowered_expr(mod, ex, ssa_offset=0) Core.NewvarNode(to_lowered_expr(mod, ex[1], ssa_offset)) elseif k == K"new_opaque_closure" args = map(e->to_lowered_expr(mod, e, ssa_offset), children(ex)) - # TODO: put allow_partial back in once we update to the latest julia - splice!(args, 4) # allow_partial Expr(:new_opaque_closure, args...) elseif k == K"meta" args = Any[to_lowered_expr(mod, e, ssa_offset) for e in children(ex)] From 0dd6c87211a35e6a499f3706696b1d7319839dee Mon Sep 17 00:00:00 2001 From: Em Chu Date: Tue, 8 Apr 2025 09:33:59 -0400 Subject: [PATCH 12/35] Adapt to different `GeneratedFunctionStub` signature Signature changed in JuliaLang/julia#57230. Thanks @aviatesk for the help! --- src/runtime.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime.jl b/src/runtime.jl index aa4a509b..85954822 100644 --- a/src/runtime.jl +++ b/src/runtime.jl @@ -282,7 +282,7 @@ end # expression into a CodeInfo. # # `args` passed into stub by the Julia runtime are (parent_func, static_params..., arg_types...) -function (g::GeneratedFunctionStub)(world::UInt, source::LineNumberNode, @nospecialize args...) +function (g::GeneratedFunctionStub)(world::UInt, source::Method, @nospecialize args...) # Some of the lowering pipeline from lower() and the pass-specific setup is # re-implemented here because generated functions are very much (but not # entirely) like macro expansion. @@ -334,7 +334,7 @@ function (g::GeneratedFunctionStub)(world::UInt, source::LineNumberNode, @nospec ctx2, ex2 = expand_forms_2( ctx1, ex1) # Wrap expansion in a non-toplevel lambda and run scope resolution - ex2 = @ast ctx2 source [K"lambda"(is_toplevel_thunk=false) + ex2 = @ast ctx2 ex0 [K"lambda"(is_toplevel_thunk=false) [K"block" (string(n)::K"Identifier" for n in g.argnames)... ] From af6a509f5acb4665b8b2cce00669417b4af978eb Mon Sep 17 00:00:00 2001 From: Em Chu Date: Tue, 8 Apr 2025 15:29:42 -0400 Subject: [PATCH 13/35] Fix `public` and `export` As of JuliaLang/julia#57765, `jl_module_public` is no longer exported. Change our runtime to handle it like `public` and `export` like we handle `import` or `using` for now --- src/runtime.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/runtime.jl b/src/runtime.jl index 85954822..23252400 100644 --- a/src/runtime.jl +++ b/src/runtime.jl @@ -209,9 +209,8 @@ function module_import(into_mod::Module, is_using::Bool, end function module_public(mod::Module, is_exported::Bool, identifiers...) - for ident in identifiers - @ccall jl_module_public(mod::Module, Symbol(ident)::Symbol, is_exported::Cint)::Cvoid - end + # symbol jl_module_public is no longer exported as of #57765 + eval(mod, Expr((is_exported ? :export : :public), map(Symbol, identifiers)...)) end #-------------------------------------------------- From fd8dd63dabe6bc644a1249f3426fe6a71b402ac9 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Tue, 8 Apr 2025 16:13:33 -0400 Subject: [PATCH 14/35] Fix modules.jl test I believe this was a world age issue --- test/modules.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/modules.jl b/test/modules.jl index 66595ee6..97cb536f 100644 --- a/test/modules.jl +++ b/test/modules.jl @@ -13,7 +13,8 @@ end @test A.g() == "hi" @test A.include isa Function @test A.Base === Base -@test A.eval(:(x = -1)) == -1 && A.x == -1 +@test A.eval(:(x = -1)) == -1 +@test A.x == -1 B = JuliaLowering.include_string(test_mod, """ baremodule B From 4f5c8776118f9b0e73ac45be90e9dccd1d7b4e6e Mon Sep 17 00:00:00 2001 From: Em Chu Date: Wed, 30 Apr 2025 16:58:18 -0700 Subject: [PATCH 15/35] Regenerate IR tests Too many to count. --- test/assignments_ir.jl | 45 +- test/closures_ir.jl | 495 +++++++------ test/decls.jl | 14 + test/decls_ir.jl | 145 ++-- test/functions_ir.jl | 1489 +++++++++++++++++++++------------------- test/generators_ir.jl | 210 +++--- test/macros_ir.jl | 40 +- test/misc_ir.jl | 9 + test/scopes_ir.jl | 81 ++- test/typedefs_ir.jl | 1065 +++++++++++++++------------- 10 files changed, 1963 insertions(+), 1630 deletions(-) diff --git a/test/assignments_ir.jl b/test/assignments_ir.jl index 9a1393c2..31fc09f1 100644 --- a/test/assignments_ir.jl +++ b/test/assignments_ir.jl @@ -31,20 +31,22 @@ begin end #--------------------- 1 (method TestMod.b) -2 TestMod.b -3 (call core.Typeof %₂) -4 (call core.svec %₃) -5 (call core.svec) -6 SourceLocation::3:9 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.b +4 (call core.Typeof %₃) +5 (call core.svec %₄) +6 (call core.svec) +7 SourceLocation::3:9 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read) slot₂/c(!read)] 1 TestMod.d 2 (= slot₂/c %₁) 3 (return %₁) -9 TestMod.b -10 (= slot₁/a %₉) -11 (return %₉) +10 (latestworld) +11 TestMod.b +12 (= slot₁/a %₁₁) +13 (return %₁₁) ######################################## # a.b = ... => setproperty! assignment @@ -117,17 +119,17 @@ end # UnionAll expansion at global scope results in const decl X{T} = Y{T,T} #--------------------- -1 (const TestMod.X) -2 (call core.TypeVar :T) -3 (= slot₁/T %₂) -4 slot₁/T -5 TestMod.Y +1 (call core.TypeVar :T) +2 (= slot₁/T %₁) +3 slot₁/T +4 TestMod.Y +5 slot₁/T 6 slot₁/T -7 slot₁/T -8 (call core.apply_type %₅ %₆ %₇) -9 (call core.UnionAll %₄ %₈) -10 (= TestMod.X %₉) -11 (return %₉) +7 (call core.apply_type %₄ %₅ %₆) +8 (call core.UnionAll %₃ %₇) +9 (constdecl TestMod.X %₈) +10 (latestworld) +11 (return %₈) ######################################## # UnionAll expansion in local scope @@ -144,7 +146,8 @@ end 7 (call core.apply_type %₄ %₅ %₆) 8 (call core.UnionAll %₃ %₇) 9 (= slot₁/X %₈) -10 (return %₈) +10 (latestworld) +11 (return %₈) ######################################## # Error: Invalid lhs in `=` diff --git a/test/closures_ir.jl b/test/closures_ir.jl index 6d6d1339..ac5246ea 100644 --- a/test/closures_ir.jl +++ b/test/closures_ir.jl @@ -15,16 +15,18 @@ end 5 (call core.svec :x) 6 (call core.svec true) 7 (call JuliaLowering.eval_closure_type TestMod :#f##0 %₅ %₆) -8 TestMod.#f##0 -9 slot₂/x -10 (new %₈ %₉) -11 (= slot₁/f %₁₀) -12 TestMod.#f##0 -13 (call core.svec %₁₂ core.Any) -14 (call core.svec) -15 SourceLocation::3:14 -16 (call core.svec %₁₃ %₁₄ %₁₅) -17 --- method core.nothing %₁₆ +8 (latestworld) +9 TestMod.#f##0 +10 slot₂/x +11 (new %₉ %₁₀) +12 (= slot₁/f %₁₁) +13 (latestworld) +14 TestMod.#f##0 +15 (call core.svec %₁₄ core.Any) +16 (call core.svec) +17 SourceLocation::3:14 +18 (call core.svec %₁₅ %₁₆ %₁₇) +19 --- method core.nothing %₁₈ slots: [slot₁/#self#(!read) slot₂/y slot₃/x(!read)] 1 TestMod.+ 2 (call core.getfield slot₁/#self# :x) @@ -36,8 +38,9 @@ end 8 (call core.getfield %₂ :contents) 9 (call %₁ %₈ slot₂/y) 10 (return %₉) -18 slot₁/f -19 (return %₁₈) +20 (latestworld) +21 slot₁/f +22 (return %₂₁) ######################################## # Closure declaration with no methods @@ -50,11 +53,13 @@ end 1 (call core.svec) 2 (call core.svec) 3 (call JuliaLowering.eval_closure_type TestMod :#no_method_f##0 %₁ %₂) -4 TestMod.#no_method_f##0 -5 (new %₄) -6 (= slot₁/no_method_f %₅) -7 slot₁/no_method_f -8 (return %₇) +4 (latestworld) +5 TestMod.#no_method_f##0 +6 (new %₅) +7 (= slot₁/no_method_f %₆) +8 (latestworld) +9 slot₁/no_method_f +10 (return %₉) ######################################## # Closure which sets the value of a captured variable @@ -72,23 +77,26 @@ end 5 (call core.svec :x) 6 (call core.svec true) 7 (call JuliaLowering.eval_closure_type TestMod :#f##1 %₅ %₆) -8 TestMod.#f##1 -9 slot₂/x -10 (new %₈ %₉) -11 (= slot₁/f %₁₀) -12 TestMod.#f##1 -13 (call core.svec %₁₂ core.Any) -14 (call core.svec) -15 SourceLocation::3:14 -16 (call core.svec %₁₃ %₁₄ %₁₅) -17 --- method core.nothing %₁₆ +8 (latestworld) +9 TestMod.#f##1 +10 slot₂/x +11 (new %₉ %₁₀) +12 (= slot₁/f %₁₁) +13 (latestworld) +14 TestMod.#f##1 +15 (call core.svec %₁₄ core.Any) +16 (call core.svec) +17 SourceLocation::3:14 +18 (call core.svec %₁₅ %₁₆ %₁₇) +19 --- method core.nothing %₁₈ slots: [slot₁/#self#(!read) slot₂/y(!read)] 1 2 2 (call core.getfield slot₁/#self# :x) 3 (call core.setfield! %₂ :contents %₁) 4 (return %₁) -18 slot₁/f -19 (return %₁₈) +20 (latestworld) +21 slot₁/f +22 (return %₂₁) ######################################## # Function where arguments are captured into a closure and assigned @@ -101,27 +109,30 @@ function f(x) end #--------------------- 1 (method TestMod.f) -2 (call core.svec :x) -3 (call core.svec true) -4 (call JuliaLowering.eval_closure_type TestMod :#f#g##0 %₂ %₃) -5 TestMod.#f#g##0 -6 (call core.svec %₅) -7 (call core.svec) -8 SourceLocation::2:14 -9 (call core.svec %₆ %₇ %₈) -10 --- method core.nothing %₉ +2 (latestworld) +3 (call core.svec :x) +4 (call core.svec true) +5 (call JuliaLowering.eval_closure_type TestMod :#f#g##0 %₃ %₄) +6 (latestworld) +7 TestMod.#f#g##0 +8 (call core.svec %₇) +9 (call core.svec) +10 SourceLocation::2:14 +11 (call core.svec %₈ %₉ %₁₀) +12 --- method core.nothing %₁₁ slots: [slot₁/#self#(!read)] 1 10 2 (call core.getfield slot₁/#self# :x) 3 (call core.setfield! %₂ :contents %₁) 4 (return %₁) -11 TestMod.f -12 (call core.Typeof %₁₁) -13 (call core.svec %₁₂ core.Any) -14 (call core.svec) -15 SourceLocation::1:10 -16 (call core.svec %₁₃ %₁₄ %₁₅) -17 --- method core.nothing %₁₆ +13 (latestworld) +14 TestMod.f +15 (call core.Typeof %₁₄) +16 (call core.svec %₁₅ core.Any) +17 (call core.svec) +18 SourceLocation::1:10 +19 (call core.svec %₁₆ %₁₇ %₁₈) +20 --- method core.nothing %₁₉ slots: [slot₁/#self#(!read) slot₂/x slot₃/g(called) slot₄/x(!read)] 1 (= slot₂/x (call core.Box slot₂/x)) 2 TestMod.#f#g##0 @@ -137,8 +148,9 @@ end 12 slot₄/x 13 (call core.getfield %₇ :contents) 14 (return %₁₃) -18 TestMod.f -19 (return %₁₈) +21 (latestworld) +22 TestMod.f +23 (return %₂₂) ######################################## # Closure where a local `x` is captured but not boxed @@ -150,26 +162,29 @@ function f(x) end #--------------------- 1 (method TestMod.f) -2 (call core.svec :x) -3 (call core.svec false) -4 (call JuliaLowering.eval_closure_type TestMod :#f#g##1 %₂ %₃) -5 TestMod.#f#g##1 -6 (call core.svec %₅) -7 (call core.svec) -8 SourceLocation::2:14 -9 (call core.svec %₆ %₇ %₈) -10 --- method core.nothing %₉ +2 (latestworld) +3 (call core.svec :x) +4 (call core.svec false) +5 (call JuliaLowering.eval_closure_type TestMod :#f#g##1 %₃ %₄) +6 (latestworld) +7 TestMod.#f#g##1 +8 (call core.svec %₇) +9 (call core.svec) +10 SourceLocation::2:14 +11 (call core.svec %₈ %₉ %₁₀) +12 --- method core.nothing %₁₁ slots: [slot₁/#self#(!read) slot₂/y(!read)] 1 (call core.getfield slot₁/#self# :x) 2 (= slot₂/y %₁) 3 (return %₁) -11 TestMod.f -12 (call core.Typeof %₁₁) -13 (call core.svec %₁₂ core.Any) -14 (call core.svec) -15 SourceLocation::1:10 -16 (call core.svec %₁₃ %₁₄ %₁₅) -17 --- method core.nothing %₁₆ +13 (latestworld) +14 TestMod.f +15 (call core.Typeof %₁₄) +16 (call core.svec %₁₅ core.Any) +17 (call core.svec) +18 SourceLocation::1:10 +19 (call core.svec %₁₆ %₁₇ %₁₈) +20 --- method core.nothing %₁₉ slots: [slot₁/#self#(!read) slot₂/x slot₃/g slot₄/z(!read)] 1 TestMod.#f#g##1 2 (call core.typeof slot₂/x) @@ -179,8 +194,9 @@ end 6 slot₂/x 7 (= slot₄/z %₆) 8 (return %₆) -18 TestMod.f -19 (return %₁₈) +21 (latestworld) +22 TestMod.f +23 (return %₂₂) ######################################## # Closure where a static parameter of an outer function is captured @@ -191,42 +207,44 @@ function f(::T) where T end #--------------------- 1 (method TestMod.f) -2 (call core.svec :T) -3 (call core.svec false) -4 (call JuliaLowering.eval_closure_type TestMod :#f#g##2 %₂ %₃) -5 TestMod.#f#g##2 -6 (call core.svec %₅) -7 (call core.svec) -8 SourceLocation::2:14 -9 (call core.svec %₆ %₇ %₈) -10 --- method core.nothing %₉ +2 (latestworld) +3 (call core.svec :T) +4 (call core.svec false) +5 (call JuliaLowering.eval_closure_type TestMod :#f#g##2 %₃ %₄) +6 (latestworld) +7 TestMod.#f#g##2 +8 (call core.svec %₇) +9 (call core.svec) +10 SourceLocation::2:14 +11 (call core.svec %₈ %₉ %₁₀) +12 --- method core.nothing %₁₁ slots: [slot₁/#self#(!read)] 1 TestMod.use 2 (call core.getfield slot₁/#self# :T) 3 (call %₁ %₂) 4 (return %₃) -11 (= slot₁/T (call core.TypeVar :T)) -12 TestMod.f -13 (call core.Typeof %₁₂) -14 slot₁/T -15 (call core.svec %₁₃ %₁₄) -16 slot₁/T -17 (call core.svec %₁₆) -18 SourceLocation::1:10 -19 (call core.svec %₁₅ %₁₇ %₁₈) -20 --- method core.nothing %₁₉ +13 (latestworld) +14 (= slot₁/T (call core.TypeVar :T)) +15 TestMod.f +16 (call core.Typeof %₁₅) +17 slot₁/T +18 (call core.svec %₁₆ %₁₇) +19 slot₁/T +20 (call core.svec %₁₉) +21 SourceLocation::1:10 +22 (call core.svec %₁₈ %₂₀ %₂₁) +23 --- method core.nothing %₂₂ slots: [slot₁/#self#(!read) slot₂/_(!read) slot₃/g] 1 TestMod.#f#g##2 - 2 static_parameter₁ - 3 (call core.typeof %₂) - 4 (call core.apply_type %₁ %₃) - 5 static_parameter₁ - 6 (new %₄ %₅) - 7 (= slot₃/g %₆) - 8 slot₃/g - 9 (return %₈) -21 TestMod.f -22 (return %₂₁) + 2 (call core.typeof static_parameter₁) + 3 (call core.apply_type %₁ %₂) + 4 (new %₃ static_parameter₁) + 5 (= slot₃/g %₄) + 6 slot₃/g + 7 (return %₆) +24 (latestworld) +25 TestMod.f +26 (return %₂₅) ######################################## # Closure captures with `isdefined` @@ -243,15 +261,17 @@ function f(x) end #--------------------- 1 (method TestMod.f) -2 (call core.svec :x :y) -3 (call core.svec false true) -4 (call JuliaLowering.eval_closure_type TestMod :#f#g##3 %₂ %₃) -5 TestMod.#f#g##3 -6 (call core.svec %₅) -7 (call core.svec) -8 SourceLocation::2:14 -9 (call core.svec %₆ %₇ %₈) -10 --- method core.nothing %₉ +2 (latestworld) +3 (call core.svec :x :y) +4 (call core.svec false true) +5 (call JuliaLowering.eval_closure_type TestMod :#f#g##3 %₃ %₄) +6 (latestworld) +7 TestMod.#f#g##3 +8 (call core.svec %₇) +9 (call core.svec) +10 SourceLocation::2:14 +11 (call core.svec %₈ %₉ %₁₀) +12 --- method core.nothing %₁₁ slots: [slot₁/#self#(!read) slot₂/z] 1 (= slot₂/z 3) 2 (call core.getfield slot₁/#self# :y) @@ -259,13 +279,14 @@ end 4 (isdefined slot₂/z) 5 (call core.tuple true %₃ %₄) 6 (return %₅) -11 TestMod.f -12 (call core.Typeof %₁₁) -13 (call core.svec %₁₂ core.Any) -14 (call core.svec) -15 SourceLocation::1:10 -16 (call core.svec %₁₃ %₁₄ %₁₅) -17 --- method core.nothing %₁₆ +13 (latestworld) +14 TestMod.f +15 (call core.Typeof %₁₄) +16 (call core.svec %₁₅ core.Any) +17 (call core.svec) +18 SourceLocation::1:10 +19 (call core.svec %₁₆ %₁₇ %₁₈) +20 --- method core.nothing %₁₉ slots: [slot₁/#self#(!read) slot₂/x slot₃/g slot₄/y] 1 (= slot₄/y (call core.Box)) 2 TestMod.#f#g##3 @@ -281,8 +302,9 @@ end 12 (call core.isdefined %₁₁ :contents) 13 (call core.tuple %₁₂ true) 14 (return %₁₃) -18 TestMod.f -19 (return %₁₈) +21 (latestworld) +22 TestMod.f +23 (return %₂₂) ######################################## # Nested captures - here `g` captures `x` because it is needed to initialize @@ -322,13 +344,14 @@ end 3 slot₁/x 4 (call core.setfield! %₃ :contents %₂) 5 (method TestMod.f) -6 TestMod.f -7 (call core.Typeof %₆) -8 (call core.svec %₇) -9 (call core.svec) -10 SourceLocation::3:14 -11 (call core.svec %₈ %₉ %₁₀) -12 --- code_info +6 (latestworld) +7 TestMod.f +8 (call core.Typeof %₇) +9 (call core.svec %₈) +10 (call core.svec) +11 SourceLocation::3:14 +12 (call core.svec %₉ %₁₀ %₁₁) +13 --- code_info slots: [slot₁/#self#(!read) slot₂/x(!read)] 1 TestMod.+ 2 (captured_local 1) @@ -342,12 +365,13 @@ end 10 (captured_local 1) 11 (call core.setfield! %₁₀ :contents %₉) 12 (return %₉) -13 slot₁/x -14 (call core.svec %₁₃) -15 (call JuliaLowering.replace_captured_locals! %₁₂ %₁₄) -16 --- method core.nothing %₁₁ %₁₅ -17 TestMod.f -18 (return %₁₇) +14 slot₁/x +15 (call core.svec %₁₄) +16 (call JuliaLowering.replace_captured_locals! %₁₃ %₁₅) +17 --- method core.nothing %₁₂ %₁₆ +18 (latestworld) +19 TestMod.f +20 (return %₁₉) ######################################## # Anonymous function syntax with -> @@ -356,19 +380,22 @@ x -> x*x 1 (call core.svec) 2 (call core.svec) 3 (call JuliaLowering.eval_closure_type TestMod :#->##0 %₁ %₂) -4 TestMod.#->##0 -5 (new %₄) -6 TestMod.#->##0 -7 (call core.svec %₆ core.Any) -8 (call core.svec) -9 SourceLocation::1:1 -10 (call core.svec %₇ %₈ %₉) -11 --- method core.nothing %₁₀ +4 (latestworld) +5 TestMod.#->##0 +6 (new %₅) +7 (latestworld) +8 TestMod.#->##0 +9 (call core.svec %₈ core.Any) +10 (call core.svec) +11 SourceLocation::1:1 +12 (call core.svec %₉ %₁₀ %₁₁) +13 --- method core.nothing %₁₂ slots: [slot₁/#self#(!read) slot₂/x] 1 TestMod.* 2 (call %₁ slot₂/x slot₂/x) 3 (return %₂) -12 (return %₅) +14 (latestworld) +15 (return %₆) ######################################## # Anonymous function syntax with `function` @@ -379,19 +406,22 @@ end 1 (call core.svec) 2 (call core.svec) 3 (call JuliaLowering.eval_closure_type TestMod :##anon###0 %₁ %₂) -4 TestMod.##anon###0 -5 (new %₄) -6 TestMod.##anon###0 -7 (call core.svec %₆ core.Any) -8 (call core.svec) -9 SourceLocation::1:10 -10 (call core.svec %₇ %₈ %₉) -11 --- method core.nothing %₁₀ +4 (latestworld) +5 TestMod.##anon###0 +6 (new %₅) +7 (latestworld) +8 TestMod.##anon###0 +9 (call core.svec %₈ core.Any) +10 (call core.svec) +11 SourceLocation::1:10 +12 (call core.svec %₉ %₁₀ %₁₁) +13 --- method core.nothing %₁₂ slots: [slot₁/#self#(!read) slot₂/x] 1 TestMod.* 2 (call %₁ slot₂/x slot₂/x) 3 (return %₂) -12 (return %₅) +14 (latestworld) +15 (return %₆) ######################################## # `do` blocks @@ -407,21 +437,25 @@ end 6 (call core.svec) 7 (call core.svec) 8 (call JuliaLowering.eval_closure_type TestMod :#do##0 %₆ %₇) -9 TestMod.#do##0 -10 (call core.svec %₉ core.Any) -11 (call core.svec) -12 SourceLocation::1:13 -13 (call core.svec %₁₀ %₁₁ %₁₂) -14 --- method core.nothing %₁₃ +9 (latestworld) +10 TestMod.#do##0 +11 (call core.svec %₁₀ core.Any) +12 (call core.svec) +13 SourceLocation::1:13 +14 (call core.svec %₁₁ %₁₂ %₁₃) +15 --- method core.nothing %₁₄ slots: [slot₁/#self#(!read) slot₂/y] 1 TestMod.+ 2 (call %₁ slot₂/y 2) 3 (return %₂) -15 TestMod.#do##0 -16 (new %₁₅) -17 TestMod.x -18 (call core.kwcall %₅ %₁ %₁₆ %₁₇) -19 (return %₁₈) +16 (latestworld) +17 (latestworld) +18 TestMod.#do##0 +19 (new %₁₈) +20 (latestworld) +21 TestMod.x +22 (call core.kwcall %₅ %₁ %₁₉ %₂₁) +23 (return %₂₂) ######################################## # Error: Static parameter clashing with closure name @@ -510,17 +544,19 @@ end 3 (call core.svec :recursive_b) 4 (call core.svec true) 5 (call JuliaLowering.eval_closure_type TestMod :#recursive_a##0 %₃ %₄) -6 TestMod.#recursive_a##0 -7 slot₂/recursive_b -8 (new %₆ %₇) -9 slot₁/recursive_a -10 (call core.setfield! %₉ :contents %₈) -11 TestMod.#recursive_a##0 -12 (call core.svec %₁₁) -13 (call core.svec) -14 SourceLocation::2:14 -15 (call core.svec %₁₂ %₁₃ %₁₄) -16 --- method core.nothing %₁₅ +6 (latestworld) +7 TestMod.#recursive_a##0 +8 slot₂/recursive_b +9 (new %₇ %₈) +10 slot₁/recursive_a +11 (call core.setfield! %₁₀ :contents %₉) +12 (latestworld) +13 TestMod.#recursive_a##0 +14 (call core.svec %₁₃) +15 (call core.svec) +16 SourceLocation::2:14 +17 (call core.svec %₁₄ %₁₅ %₁₆) +18 --- method core.nothing %₁₇ slots: [slot₁/#self#(!read) slot₂/recursive_b(!read)] 1 (call core.getfield slot₁/#self# :recursive_b) 2 (call core.isdefined %₁ :contents) @@ -531,20 +567,23 @@ end 7 (call core.getfield %₁ :contents) 8 (call %₇) 9 (return %₈) -17 (call core.svec :recursive_a) -18 (call core.svec true) -19 (call JuliaLowering.eval_closure_type TestMod :#recursive_b##0 %₁₇ %₁₈) -20 TestMod.#recursive_b##0 -21 slot₁/recursive_a -22 (new %₂₀ %₂₁) -23 slot₂/recursive_b -24 (call core.setfield! %₂₃ :contents %₂₂) -25 TestMod.#recursive_b##0 -26 (call core.svec %₂₅) -27 (call core.svec) -28 SourceLocation::5:14 -29 (call core.svec %₂₆ %₂₇ %₂₈) -30 --- method core.nothing %₂₉ +19 (latestworld) +20 (call core.svec :recursive_a) +21 (call core.svec true) +22 (call JuliaLowering.eval_closure_type TestMod :#recursive_b##0 %₂₀ %₂₁) +23 (latestworld) +24 TestMod.#recursive_b##0 +25 slot₁/recursive_a +26 (new %₂₄ %₂₅) +27 slot₂/recursive_b +28 (call core.setfield! %₂₇ :contents %₂₆) +29 (latestworld) +30 TestMod.#recursive_b##0 +31 (call core.svec %₃₀) +32 (call core.svec) +33 SourceLocation::5:14 +34 (call core.svec %₃₁ %₃₂ %₃₃) +35 --- method core.nothing %₃₄ slots: [slot₁/#self#(!read) slot₂/recursive_a(!read)] 1 (call core.getfield slot₁/#self# :recursive_a) 2 (call core.isdefined %₁ :contents) @@ -555,14 +594,15 @@ end 7 (call core.getfield %₁ :contents) 8 (call %₇) 9 (return %₈) -31 slot₂/recursive_b -32 (call core.isdefined %₃₁ :contents) -33 (gotoifnot %₃₂ label₃₅) -34 (goto label₃₇) -35 (newvar slot₄/recursive_b) -36 slot₄/recursive_b -37 (call core.getfield %₃₁ :contents) -38 (return %₃₇) +36 (latestworld) +37 slot₂/recursive_b +38 (call core.isdefined %₃₇ :contents) +39 (gotoifnot %₃₈ label₄₁) +40 (goto label₄₃) +41 (newvar slot₄/recursive_b) +42 slot₄/recursive_b +43 (call core.getfield %₃₇ :contents) +44 (return %₄₃) ######################################## # Closure with keywords @@ -580,26 +620,29 @@ end 6 (call core.svec :#f_kw_closure#0) 7 (call core.svec true) 8 (call JuliaLowering.eval_closure_type TestMod :#f_kw_closure##0 %₆ %₇) -9 TestMod.#f_kw_closure##0 -10 slot₂/#f_kw_closure#0 -11 (new %₉ %₁₀) -12 (= slot₃/f_kw_closure %₁₁) -13 (call core.svec :y) -14 (call core.svec true) -15 (call JuliaLowering.eval_closure_type TestMod :##f_kw_closure#0##0 %₁₃ %₁₄) -16 TestMod.##f_kw_closure#0##0 -17 slot₁/y -18 (new %₁₆ %₁₇) -19 slot₂/#f_kw_closure#0 -20 (call core.setfield! %₁₉ :contents %₁₈) -21 TestMod.##f_kw_closure#0##0 -22 TestMod.X -23 TestMod.#f_kw_closure##0 -24 (call core.svec %₂₁ %₂₂ %₂₃) -25 (call core.svec) -26 SourceLocation::2:14 +9 (latestworld) +10 TestMod.#f_kw_closure##0 +11 slot₂/#f_kw_closure#0 +12 (new %₁₀ %₁₁) +13 (= slot₃/f_kw_closure %₁₂) +14 (call core.svec :y) +15 (call core.svec true) +16 (call JuliaLowering.eval_closure_type TestMod :##f_kw_closure#0##0 %₁₄ %₁₅) +17 (latestworld) +18 TestMod.##f_kw_closure#0##0 +19 slot₁/y +20 (new %₁₈ %₁₉) +21 slot₂/#f_kw_closure#0 +22 (call core.setfield! %₂₁ :contents %₂₀) +23 (latestworld) +24 TestMod.##f_kw_closure#0##0 +25 TestMod.X +26 TestMod.#f_kw_closure##0 27 (call core.svec %₂₄ %₂₅ %₂₆) -28 --- method core.nothing %₂₇ +28 (call core.svec) +29 SourceLocation::2:14 +30 (call core.svec %₂₇ %₂₈ %₂₉) +31 --- method core.nothing %₃₀ slots: [slot₁/#self#(!read) slot₂/x slot₃/#self#(!read) slot₄/y(!read)] 1 (meta :nkw 1) 2 TestMod.+ @@ -612,13 +655,14 @@ end 9 (call core.getfield %₃ :contents) 10 (call %₂ slot₂/x %₉) 11 (return %₁₀) -29 (call core.typeof core.kwcall) -30 TestMod.#f_kw_closure##0 -31 (call core.svec %₂₉ core.NamedTuple %₃₀) -32 (call core.svec) -33 SourceLocation::2:14 -34 (call core.svec %₃₁ %₃₂ %₃₃) -35 --- code_info +32 (latestworld) +33 (call core.typeof core.kwcall) +34 TestMod.#f_kw_closure##0 +35 (call core.svec %₃₃ core.NamedTuple %₃₄) +36 (call core.svec) +37 SourceLocation::2:14 +38 (call core.svec %₃₅ %₃₆ %₃₇) +39 --- code_info slots: [slot₁/#self#(!read) slot₂/kws slot₃/#self# slot₄/kwtmp slot₅/x(!read) slot₆/#f_kw_closure#0(!read)] 1 (newvar slot₅/x) 2 (call core.isdefined slot₂/kws :x) @@ -652,16 +696,18 @@ end 30 (call core.getfield %₂₄ :contents) 31 (call %₃₀ %₁₆ slot₃/#self#) 32 (return %₃₁) -36 slot₂/#f_kw_closure#0 -37 (call core.svec %₃₆) -38 (call JuliaLowering.replace_captured_locals! %₃₅ %₃₇) -39 --- method core.nothing %₃₄ %₃₈ -40 TestMod.#f_kw_closure##0 +40 slot₂/#f_kw_closure#0 41 (call core.svec %₄₀) -42 (call core.svec) -43 SourceLocation::2:14 -44 (call core.svec %₄₁ %₄₂ %₄₃) -45 --- method core.nothing %₄₄ +42 (call JuliaLowering.replace_captured_locals! %₃₉ %₄₁) +43 --- method core.nothing %₃₈ %₄₂ +44 (latestworld) +45 (latestworld) +46 TestMod.#f_kw_closure##0 +47 (call core.svec %₄₆) +48 (call core.svec) +49 SourceLocation::2:14 +50 (call core.svec %₄₇ %₄₈ %₄₉) +51 --- method core.nothing %₅₀ slots: [slot₁/#self# slot₂/#f_kw_closure#0(!read)] 1 (call core.getfield slot₁/#self# :#f_kw_closure#0) 2 (call core.isdefined %₁ :contents) @@ -673,8 +719,9 @@ end 8 TestMod.x_default 9 (call %₇ %₈ slot₁/#self#) 10 (return %₉) -46 slot₃/f_kw_closure -47 (return %₄₆) +52 (latestworld) +53 slot₃/f_kw_closure +54 (return %₅₃) ######################################## # Closure capturing a typed local must also capture the type expression diff --git a/test/decls.jl b/test/decls.jl index 08484dfa..f56e7d3b 100644 --- a/test/decls.jl +++ b/test/decls.jl @@ -49,4 +49,18 @@ end @test Core.get_binding_type(test_mod, :a_typed_global_2) === Int @test test_mod.a_typed_global_2 === 10 +# Const and tuple assignments +@test JuliaLowering.include_string(test_mod, "(a0, a1, a2) = [1,2,3]") == [1,2,3] + +@test JuliaLowering.include_string(test_mod, "const abc::Int = 9") === 9 + +# redeclaration of the same value used to be allowed +@test_throws ErrorException JuliaLowering.include_string(test_mod, "abc = 9") +@test_throws ErrorException JuliaLowering.include_string(test_mod, "abc = 10") +# redeclaration with const should be OK +@test JuliaLowering.include_string(test_mod, "const abc::Int = 0") === 0 + +# Unsupported for now +@test_throws LoweringError JuliaLowering.include_string(test_mod, "const a,b,c = 1,2,3") + end diff --git a/test/decls_ir.jl b/test/decls_ir.jl index a8b9fd98..30848d48 100644 --- a/test/decls_ir.jl +++ b/test/decls_ir.jl @@ -21,63 +21,108 @@ local x::T = 1 # const const xx = 10 #--------------------- -1 (const TestMod.xx) -2 (= TestMod.xx 10) -3 (return 10) +1 10 +2 (constdecl TestMod.xx %₁) +3 (latestworld) +4 (return %₁) ######################################## # Typed const const xx::T = 10 #--------------------- 1 TestMod.T -2 (call core.set_binding_type! TestMod :xx %₁) -3 (const TestMod.xx) -4 (call core.get_binding_type TestMod :xx) -5 (= slot₁/tmp 10) -6 slot₁/tmp -7 (call core.isa %₆ %₄) -8 (gotoifnot %₇ label₁₀) -9 (goto label₁₂) +2 (= slot₁/tmp 10) +3 slot₁/tmp +4 (call core.isa %₃ %₁) +5 (gotoifnot %₄ label₇) +6 (goto label₁₀) +7 slot₁/tmp +8 (call top.convert %₁ %₇) +9 (= slot₁/tmp (call core.typeassert %₈ %₁)) 10 slot₁/tmp -11 (= slot₁/tmp (call top.convert %₄ %₁₀)) -12 slot₁/tmp -13 (= TestMod.xx %₁₂) -14 (return 10) +11 (constdecl TestMod.xx %₁₀) +12 (latestworld) +13 (return %₁₀) + +######################################## +# Error: Const tuple +const xxx,xxxx,xxxxx = 10,20,30 +#--------------------- +LoweringError: +const xxx,xxxx,xxxxx = 10,20,30 +# └─────────────┘ ── unsupported `const` tuple + +######################################## +# Const in chain: only first is const +const c0 = v0 = v1 = 123 +#--------------------- +1 123 +2 (constdecl TestMod.c0 %₁) +3 (globaldecl TestMod.v0) +4 (latestworld) +5 (call core.get_binding_type TestMod :v0) +6 (= slot₁/tmp %₁) +7 slot₁/tmp +8 (call core.isa %₇ %₅) +9 (gotoifnot %₈ label₁₁) +10 (goto label₁₃) +11 slot₁/tmp +12 (= slot₁/tmp (call top.convert %₅ %₁₁)) +13 slot₁/tmp +14 (call top.setglobal! TestMod :v0 %₁₃) +15 (globaldecl TestMod.v1) +16 (latestworld) +17 (call core.get_binding_type TestMod :v1) +18 (= slot₂/tmp %₁) +19 slot₂/tmp +20 (call core.isa %₁₉ %₁₇) +21 (gotoifnot %₂₀ label₂₃) +22 (goto label₂₅) +23 slot₂/tmp +24 (= slot₂/tmp (call top.convert %₁₇ %₂₃)) +25 slot₂/tmp +26 (call top.setglobal! TestMod :v1 %₂₅) +27 (return %₁) ######################################## # Global assignment xx = 10 #--------------------- -1 (call core.get_binding_type TestMod :xx) -2 (= slot₁/tmp 10) -3 slot₁/tmp -4 (call core.isa %₃ %₁) -5 (gotoifnot %₄ label₇) -6 (goto label₉) -7 slot₁/tmp -8 (= slot₁/tmp (call top.convert %₁ %₇)) +1 (globaldecl TestMod.xx) +2 (latestworld) +3 (call core.get_binding_type TestMod :xx) +4 (= slot₁/tmp 10) +5 slot₁/tmp +6 (call core.isa %₅ %₃) +7 (gotoifnot %₆ label₉) +8 (goto label₁₁) 9 slot₁/tmp -10 (= TestMod.xx %₉) -11 (return 10) +10 (= slot₁/tmp (call top.convert %₃ %₉)) +11 slot₁/tmp +12 (call top.setglobal! TestMod :xx %₁₁) +13 (return 10) ######################################## # Typed global assignment global xx::T = 10 #--------------------- -1 TestMod.T -2 (call core.set_binding_type! TestMod :xx %₁) +1 (globaldecl TestMod.xx TestMod.T) +2 (latestworld) 3 (global TestMod.xx) -4 (call core.get_binding_type TestMod :xx) -5 (= slot₁/tmp 10) -6 slot₁/tmp -7 (call core.isa %₆ %₄) -8 (gotoifnot %₇ label₁₀) -9 (goto label₁₂) -10 slot₁/tmp -11 (= slot₁/tmp (call top.convert %₄ %₁₀)) -12 slot₁/tmp -13 (= TestMod.xx %₁₂) -14 (return 10) +4 (latestworld) +5 (globaldecl TestMod.xx) +6 (latestworld) +7 (call core.get_binding_type TestMod :xx) +8 (= slot₁/tmp 10) +9 slot₁/tmp +10 (call core.isa %₉ %₇) +11 (gotoifnot %₁₀ label₁₃) +12 (goto label₁₅) +13 slot₁/tmp +14 (= slot₁/tmp (call top.convert %₇ %₁₃)) +15 slot₁/tmp +16 (call top.setglobal! TestMod :xx %₁₅) +17 (return 10) ######################################## # Error: x declared twice @@ -99,7 +144,7 @@ const local x = 1 #--------------------- LoweringError: const local x = 1 -# ╙ ── unsupported `const` declaration on local variable +└───────────────┘ ── unsupported `const local` declaration ######################################## # Error: Const not supported on locals @@ -110,7 +155,7 @@ end LoweringError: let const x = 1 -# ╙ ── unsupported `const` declaration on local variable +# └────┘ ── unsupported `const` declaration on local variable end ######################################## @@ -122,13 +167,14 @@ function f(x) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃ core.Any) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄ core.Any) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read) slot₂/x slot₃/tmp(!read) slot₄/tmp(!read)] 1 1 2 TestMod.Int @@ -156,8 +202,9 @@ end 24 (= slot₂/x %₂₃) 25 slot₂/x 26 (return %₂₅) -9 TestMod.f -10 (return %₉) +10 (latestworld) +11 TestMod.f +12 (return %₁₁) ######################################## # Error: global type decls only allowed at top level diff --git a/test/functions_ir.jl b/test/functions_ir.jl index 9abb27e9..5f701b39 100644 --- a/test/functions_ir.jl +++ b/test/functions_ir.jl @@ -4,8 +4,9 @@ function f end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (return %₂) +2 (latestworld) +3 TestMod.f +4 (return %₃) ######################################## # Functions with placeholder arg @@ -14,19 +15,21 @@ function f(x, _, y) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃ core.Any core.Any core.Any) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄ core.Any core.Any core.Any) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read) slot₂/x slot₃/_(!read) slot₄/y] 1 TestMod.+ 2 (call %₁ slot₂/x slot₄/y) 3 (return %₂) -9 TestMod.f -10 (return %₉) +10 (latestworld) +11 TestMod.f +12 (return %₁₁) ######################################## # Functions with argument types only, no name @@ -35,19 +38,21 @@ function f(::T, x) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 TestMod.T -5 (call core.svec %₃ %₄ core.Any) -6 (call core.svec) -7 SourceLocation::1:10 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 TestMod.T +6 (call core.svec %₄ %₅ core.Any) +7 (call core.svec) +8 SourceLocation::1:10 +9 (call core.svec %₆ %₇ %₈) +10 --- method core.nothing %₉ slots: [slot₁/#self#(!read) slot₂/_(!read) slot₃/x] 1 slot₃/x 2 (return %₁) -10 TestMod.f -11 (return %₁₀) +11 (latestworld) +12 TestMod.f +13 (return %₁₂) ######################################## # Functions argument types @@ -56,19 +61,21 @@ function f(x, y::T) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 TestMod.T -5 (call core.svec %₃ core.Any %₄) -6 (call core.svec) -7 SourceLocation::1:10 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 TestMod.T +6 (call core.svec %₄ core.Any %₅) +7 (call core.svec) +8 SourceLocation::1:10 +9 (call core.svec %₆ %₇ %₈) +10 --- method core.nothing %₉ slots: [slot₁/#self#(!read) slot₂/x(!read) slot₃/y(!read)] 1 TestMod.body 2 (return %₁) -10 TestMod.f -11 (return %₁₀) +11 (latestworld) +12 TestMod.f +13 (return %₁₂) ######################################## # Functions with slurp of Any @@ -77,19 +84,21 @@ function f(x, ys...) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.apply_type core.Vararg core.Any) -5 (call core.svec %₃ core.Any %₄) -6 (call core.svec) -7 SourceLocation::1:10 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.apply_type core.Vararg core.Any) +6 (call core.svec %₄ core.Any %₅) +7 (call core.svec) +8 SourceLocation::1:10 +9 (call core.svec %₆ %₇ %₈) +10 --- method core.nothing %₉ slots: [slot₁/#self#(!read) slot₂/x(!read) slot₃/ys(!read)] 1 TestMod.body 2 (return %₁) -10 TestMod.f -11 (return %₁₀) +11 (latestworld) +12 TestMod.f +13 (return %₁₂) ######################################## # Functions with slurp of T @@ -98,20 +107,22 @@ function f(x, ys::T...) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 TestMod.T -5 (call core.apply_type core.Vararg %₄) -6 (call core.svec %₃ core.Any %₅) -7 (call core.svec) -8 SourceLocation::1:10 -9 (call core.svec %₆ %₇ %₈) -10 --- method core.nothing %₉ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 TestMod.T +6 (call core.apply_type core.Vararg %₅) +7 (call core.svec %₄ core.Any %₆) +8 (call core.svec) +9 SourceLocation::1:10 +10 (call core.svec %₇ %₈ %₉) +11 --- method core.nothing %₁₀ slots: [slot₁/#self#(!read) slot₂/x(!read) slot₃/ys(!read)] 1 TestMod.body 2 (return %₁) -11 TestMod.f -12 (return %₁₁) +12 (latestworld) +13 TestMod.f +14 (return %₁₃) ######################################## # Error: Function with slurp not in last position arg @@ -132,30 +143,29 @@ function f(::T, ::U, ::V) where T where {U,V} end #--------------------- 1 (method TestMod.f) -2 (= slot₂/U (call core.TypeVar :U)) -3 (= slot₃/V (call core.TypeVar :V)) -4 (= slot₁/T (call core.TypeVar :T)) -5 TestMod.f -6 (call core.Typeof %₅) -7 slot₁/T -8 slot₂/U -9 slot₃/V -10 (call core.svec %₆ %₇ %₈ %₉) -11 slot₂/U -12 slot₃/V -13 slot₁/T -14 (call core.svec %₁₁ %₁₂ %₁₃) -15 SourceLocation::1:10 -16 (call core.svec %₁₀ %₁₄ %₁₅) -17 --- method core.nothing %₁₆ +2 (latestworld) +3 (= slot₂/U (call core.TypeVar :U)) +4 (= slot₃/V (call core.TypeVar :V)) +5 (= slot₁/T (call core.TypeVar :T)) +6 TestMod.f +7 (call core.Typeof %₆) +8 slot₁/T +9 slot₂/U +10 slot₃/V +11 (call core.svec %₇ %₈ %₉ %₁₀) +12 slot₂/U +13 slot₃/V +14 slot₁/T +15 (call core.svec %₁₂ %₁₃ %₁₄) +16 SourceLocation::1:10 +17 (call core.svec %₁₁ %₁₅ %₁₆) +18 --- method core.nothing %₁₇ slots: [slot₁/#self#(!read) slot₂/_(!read) slot₃/_(!read) slot₄/_(!read)] - 1 static_parameter₃ - 2 static_parameter₁ - 3 static_parameter₂ - 4 (call core.tuple %₁ %₂ %₃) - 5 (return %₄) -18 TestMod.f -19 (return %₁₈) + 1 (call core.tuple static_parameter₃ static_parameter₁ static_parameter₂) + 2 (return %₁) +19 (latestworld) +20 TestMod.f +21 (return %₂₀) ######################################## # Static parameter with bounds and used with apply_type in argument @@ -164,25 +174,26 @@ function f(::S{T}) where X <: T <: Y end #--------------------- 1 (method TestMod.f) -2 TestMod.X -3 TestMod.Y -4 (= slot₁/T (call core.TypeVar :T %₂ %₃)) -5 TestMod.f -6 (call core.Typeof %₅) -7 TestMod.S -8 slot₁/T -9 (call core.apply_type %₇ %₈) -10 (call core.svec %₆ %₉) -11 slot₁/T -12 (call core.svec %₁₁) -13 SourceLocation::1:10 -14 (call core.svec %₁₀ %₁₂ %₁₃) -15 --- method core.nothing %₁₄ +2 (latestworld) +3 TestMod.X +4 TestMod.Y +5 (= slot₁/T (call core.TypeVar :T %₃ %₄)) +6 TestMod.f +7 (call core.Typeof %₆) +8 TestMod.S +9 slot₁/T +10 (call core.apply_type %₈ %₉) +11 (call core.svec %₇ %₁₀) +12 slot₁/T +13 (call core.svec %₁₂) +14 SourceLocation::1:10 +15 (call core.svec %₁₁ %₁₃ %₁₄) +16 --- method core.nothing %₁₅ slots: [slot₁/#self#(!read) slot₂/_(!read)] - 1 static_parameter₁ - 2 (return %₁) -16 TestMod.f -17 (return %₁₆) + 1 (return static_parameter₁) +17 (latestworld) +18 TestMod.f +19 (return %₁₈) ######################################## # Static parameter which is used only in the bounds of another static parameter @@ -192,28 +203,28 @@ function f(x, y::S) where {T, S<:AbstractVector{T}} end #--------------------- 1 (method TestMod.f) -2 (= slot₂/T (call core.TypeVar :T)) -3 TestMod.AbstractVector -4 slot₂/T -5 (call core.apply_type %₃ %₄) -6 (= slot₁/S (call core.TypeVar :S %₅)) -7 TestMod.f -8 (call core.Typeof %₇) -9 slot₁/S -10 (call core.svec %₈ core.Any %₉) -11 slot₂/T -12 slot₁/S -13 (call core.svec %₁₁ %₁₂) -14 SourceLocation::1:10 -15 (call core.svec %₁₀ %₁₃ %₁₄) -16 --- method core.nothing %₁₅ +2 (latestworld) +3 (= slot₂/T (call core.TypeVar :T)) +4 TestMod.AbstractVector +5 slot₂/T +6 (call core.apply_type %₄ %₅) +7 (= slot₁/S (call core.TypeVar :S %₆)) +8 TestMod.f +9 (call core.Typeof %₈) +10 slot₁/S +11 (call core.svec %₉ core.Any %₁₀) +12 slot₂/T +13 slot₁/S +14 (call core.svec %₁₂ %₁₃) +15 SourceLocation::1:10 +16 (call core.svec %₁₁ %₁₄ %₁₅) +17 --- method core.nothing %₁₆ slots: [slot₁/#self#(!read) slot₂/x(!read) slot₃/y(!read)] - 1 static_parameter₁ - 2 static_parameter₂ - 3 (call core.tuple %₁ %₂) - 4 (return %₃) -17 TestMod.f -18 (return %₁₇) + 1 (call core.tuple static_parameter₁ static_parameter₂) + 2 (return %₁) +18 (latestworld) +19 TestMod.f +20 (return %₁₉) ######################################## # Error: Static parameter which is unused @@ -237,13 +248,14 @@ function f(x)::Int end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃ core.Any) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄ core.Any) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read) slot₂/x slot₃/tmp(!read)] 1 TestMod.Int 2 (gotoifnot slot₂/x label₃) @@ -257,8 +269,9 @@ end 10 (= slot₃/tmp (call core.typeassert %₉ %₁)) 11 slot₃/tmp 12 (return %₁₁) -9 TestMod.f -10 (return %₉) +10 (latestworld) +11 TestMod.f +12 (return %₁₁) ######################################## # Callable type @@ -266,16 +279,18 @@ function (::T)(x) x end #--------------------- -1 TestMod.T -2 (call core.svec %₁ core.Any) -3 (call core.svec) -4 SourceLocation::1:10 -5 (call core.svec %₂ %₃ %₄) -6 --- method core.nothing %₅ +1 (latestworld) +2 TestMod.T +3 (call core.svec %₂ core.Any) +4 (call core.svec) +5 SourceLocation::1:10 +6 (call core.svec %₃ %₄ %₅) +7 --- method core.nothing %₆ slots: [slot₁/#self#(!read) slot₂/x] 1 slot₂/x 2 (return %₁) -7 (return core.nothing) +8 (latestworld) +9 (return core.nothing) ######################################## # Callable type with instance @@ -283,16 +298,18 @@ function (y::T)(x) (y, x) end #--------------------- -1 TestMod.T -2 (call core.svec %₁ core.Any) -3 (call core.svec) -4 SourceLocation::1:10 -5 (call core.svec %₂ %₃ %₄) -6 --- method core.nothing %₅ +1 (latestworld) +2 TestMod.T +3 (call core.svec %₂ core.Any) +4 (call core.svec) +5 SourceLocation::1:10 +6 (call core.svec %₃ %₄ %₅) +7 --- method core.nothing %₆ slots: [slot₁/y slot₂/x] 1 (call core.tuple slot₁/y slot₂/x) 2 (return %₁) -7 (return core.nothing) +8 (latestworld) +9 (return core.nothing) ######################################## # `where` params used in callable object type @@ -300,37 +317,40 @@ function (x::X1{T})() where T T end #--------------------- -1 (= slot₁/T (call core.TypeVar :T)) -2 TestMod.X1 -3 slot₁/T -4 (call core.apply_type %₂ %₃) -5 (call core.svec %₄) -6 slot₁/T -7 (call core.svec %₆) -8 SourceLocation::1:10 -9 (call core.svec %₅ %₇ %₈) -10 --- method core.nothing %₉ +1 (latestworld) +2 (= slot₁/T (call core.TypeVar :T)) +3 TestMod.X1 +4 slot₁/T +5 (call core.apply_type %₃ %₄) +6 (call core.svec %₅) +7 slot₁/T +8 (call core.svec %₇) +9 SourceLocation::1:10 +10 (call core.svec %₆ %₈ %₉) +11 --- method core.nothing %₁₀ slots: [slot₁/x(!read)] - 1 static_parameter₁ - 2 (return %₁) -11 (return core.nothing) + 1 (return static_parameter₁) +12 (latestworld) +13 (return core.nothing) ######################################## # Function with module ref in name function A.f() end #--------------------- -1 TestMod.A -2 (call top.getproperty %₁ :f) -3 (call core.Typeof %₂) -4 (call core.svec %₃) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +1 (latestworld) +2 TestMod.A +3 (call top.getproperty %₂ :f) +4 (call core.Typeof %₃) +5 (call core.svec %₄) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read)] 1 (return core.nothing) -9 (return core.nothing) +10 (latestworld) +11 (return core.nothing) ######################################## # Error: Invalid dotop function name @@ -359,44 +379,48 @@ function f(x::T, y::S=1, z::U=2) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 TestMod.T -5 (call core.svec %₃ %₄) -6 (call core.svec) -7 SourceLocation::1:10 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 TestMod.T +6 (call core.svec %₄ %₅) +7 (call core.svec) +8 SourceLocation::1:10 +9 (call core.svec %₆ %₇ %₈) +10 --- method core.nothing %₉ slots: [slot₁/#self#(called) slot₂/x] 1 (call slot₁/#self# slot₂/x 1 2) 2 (return %₁) -10 TestMod.f -11 (call core.Typeof %₁₀) -12 TestMod.T -13 TestMod.S -14 (call core.svec %₁₁ %₁₂ %₁₃) -15 (call core.svec) -16 SourceLocation::1:10 -17 (call core.svec %₁₄ %₁₅ %₁₆) -18 --- method core.nothing %₁₇ +11 (latestworld) +12 TestMod.f +13 (call core.Typeof %₁₂) +14 TestMod.T +15 TestMod.S +16 (call core.svec %₁₃ %₁₄ %₁₅) +17 (call core.svec) +18 SourceLocation::1:10 +19 (call core.svec %₁₆ %₁₇ %₁₈) +20 --- method core.nothing %₁₉ slots: [slot₁/#self#(called) slot₂/x slot₃/y] 1 (call slot₁/#self# slot₂/x slot₃/y 2) 2 (return %₁) -19 TestMod.f -20 (call core.Typeof %₁₉) -21 TestMod.T -22 TestMod.S -23 TestMod.U -24 (call core.svec %₂₀ %₂₁ %₂₂ %₂₃) -25 (call core.svec) -26 SourceLocation::1:10 -27 (call core.svec %₂₄ %₂₅ %₂₆) -28 --- method core.nothing %₂₇ +21 (latestworld) +22 TestMod.f +23 (call core.Typeof %₂₂) +24 TestMod.T +25 TestMod.S +26 TestMod.U +27 (call core.svec %₂₃ %₂₄ %₂₅ %₂₆) +28 (call core.svec) +29 SourceLocation::1:10 +30 (call core.svec %₂₇ %₂₈ %₂₉) +31 --- method core.nothing %₃₀ slots: [slot₁/#self#(!read) slot₂/x slot₃/y slot₄/z(!read)] 1 (call core.tuple slot₂/x slot₃/y) 2 (return %₁) -29 TestMod.f -30 (return %₂₉) +32 (latestworld) +33 TestMod.f +34 (return %₃₃) ######################################## # Default positional args which depend on other args @@ -405,38 +429,42 @@ function f(x=1, y=x) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(called)] 1 (call slot₁/#self# 1) 2 (return %₁) -9 TestMod.f -10 (call core.Typeof %₉) -11 (call core.svec %₁₀ core.Any) -12 (call core.svec) -13 SourceLocation::1:10 -14 (call core.svec %₁₁ %₁₂ %₁₃) -15 --- method core.nothing %₁₄ +10 (latestworld) +11 TestMod.f +12 (call core.Typeof %₁₁) +13 (call core.svec %₁₂ core.Any) +14 (call core.svec) +15 SourceLocation::1:10 +16 (call core.svec %₁₃ %₁₄ %₁₅) +17 --- method core.nothing %₁₆ slots: [slot₁/#self#(called) slot₂/x] 1 (call slot₁/#self# slot₂/x slot₂/x) 2 (return %₁) -16 TestMod.f -17 (call core.Typeof %₁₆) -18 (call core.svec %₁₇ core.Any core.Any) -19 (call core.svec) -20 SourceLocation::1:10 -21 (call core.svec %₁₈ %₁₉ %₂₀) -22 --- method core.nothing %₂₁ +18 (latestworld) +19 TestMod.f +20 (call core.Typeof %₁₉) +21 (call core.svec %₂₀ core.Any core.Any) +22 (call core.svec) +23 SourceLocation::1:10 +24 (call core.svec %₂₁ %₂₂ %₂₃) +25 --- method core.nothing %₂₄ slots: [slot₁/#self#(!read) slot₂/x slot₃/y] 1 (call core.tuple slot₂/x slot₃/y) 2 (return %₁) -23 TestMod.f -24 (return %₂₃) +26 (latestworld) +27 TestMod.f +28 (return %₂₇) ######################################## # Default positional args with missing arg names (implicit placeholders) @@ -445,41 +473,45 @@ function f(::Int, y=1, z=2) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 TestMod.Int -5 (call core.svec %₃ %₄) -6 (call core.svec) -7 SourceLocation::1:10 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 TestMod.Int +6 (call core.svec %₄ %₅) +7 (call core.svec) +8 SourceLocation::1:10 +9 (call core.svec %₆ %₇ %₈) +10 --- method core.nothing %₉ slots: [slot₁/#self#(called) slot₂/_] 1 (call slot₁/#self# slot₂/_ 1 2) 2 (return %₁) -10 TestMod.f -11 (call core.Typeof %₁₀) -12 TestMod.Int -13 (call core.svec %₁₁ %₁₂ core.Any) -14 (call core.svec) -15 SourceLocation::1:10 -16 (call core.svec %₁₃ %₁₄ %₁₅) -17 --- method core.nothing %₁₆ +11 (latestworld) +12 TestMod.f +13 (call core.Typeof %₁₂) +14 TestMod.Int +15 (call core.svec %₁₃ %₁₄ core.Any) +16 (call core.svec) +17 SourceLocation::1:10 +18 (call core.svec %₁₅ %₁₆ %₁₇) +19 --- method core.nothing %₁₈ slots: [slot₁/#self#(called) slot₂/_ slot₃/y] 1 (call slot₁/#self# slot₂/_ slot₃/y 2) 2 (return %₁) -18 TestMod.f -19 (call core.Typeof %₁₈) -20 TestMod.Int -21 (call core.svec %₁₉ %₂₀ core.Any core.Any) -22 (call core.svec) -23 SourceLocation::1:10 -24 (call core.svec %₂₁ %₂₂ %₂₃) -25 --- method core.nothing %₂₄ +20 (latestworld) +21 TestMod.f +22 (call core.Typeof %₂₁) +23 TestMod.Int +24 (call core.svec %₂₂ %₂₃ core.Any core.Any) +25 (call core.svec) +26 SourceLocation::1:10 +27 (call core.svec %₂₄ %₂₅ %₂₆) +28 --- method core.nothing %₂₇ slots: [slot₁/#self#(!read) slot₂/_(!read) slot₃/y slot₄/z] 1 (call core.tuple slot₃/y slot₄/z) 2 (return %₁) -26 TestMod.f -27 (return %₂₆) +29 (latestworld) +30 TestMod.f +31 (return %₃₀) ######################################## # Default positional args with placeholders @@ -488,30 +520,33 @@ function f(_::Int, x=1) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 TestMod.Int -5 (call core.svec %₃ %₄) -6 (call core.svec) -7 SourceLocation::1:10 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 TestMod.Int +6 (call core.svec %₄ %₅) +7 (call core.svec) +8 SourceLocation::1:10 +9 (call core.svec %₆ %₇ %₈) +10 --- method core.nothing %₉ slots: [slot₁/#self#(called) slot₂/_] 1 (call slot₁/#self# slot₂/_ 1) 2 (return %₁) -10 TestMod.f -11 (call core.Typeof %₁₀) -12 TestMod.Int -13 (call core.svec %₁₁ %₁₂ core.Any) -14 (call core.svec) -15 SourceLocation::1:10 -16 (call core.svec %₁₃ %₁₄ %₁₅) -17 --- method core.nothing %₁₆ +11 (latestworld) +12 TestMod.f +13 (call core.Typeof %₁₂) +14 TestMod.Int +15 (call core.svec %₁₃ %₁₄ core.Any) +16 (call core.svec) +17 SourceLocation::1:10 +18 (call core.svec %₁₅ %₁₆ %₁₇) +19 --- method core.nothing %₁₈ slots: [slot₁/#self#(!read) slot₂/_(!read) slot₃/x] 1 slot₃/x 2 (return %₁) -18 TestMod.f -19 (return %₁₈) +20 (latestworld) +21 TestMod.f +22 (return %₂₁) ######################################## # Positional args with defaults and `where` clauses @@ -520,55 +555,59 @@ function f(x::T, y::S=1, z::U=2) where {T,S<:T,U<:S} end #--------------------- 1 (method TestMod.f) -2 (= slot₂/T (call core.TypeVar :T)) -3 slot₂/T -4 (= slot₁/S (call core.TypeVar :S %₃)) -5 slot₁/S -6 (= slot₃/U (call core.TypeVar :U %₅)) -7 TestMod.f -8 (call core.Typeof %₇) -9 slot₂/T -10 (call core.svec %₈ %₉) -11 slot₂/T -12 (call core.svec %₁₁) -13 SourceLocation::1:10 -14 (call core.svec %₁₀ %₁₂ %₁₃) -15 --- method core.nothing %₁₄ +2 (latestworld) +3 (= slot₂/T (call core.TypeVar :T)) +4 slot₂/T +5 (= slot₁/S (call core.TypeVar :S %₄)) +6 slot₁/S +7 (= slot₃/U (call core.TypeVar :U %₆)) +8 TestMod.f +9 (call core.Typeof %₈) +10 slot₂/T +11 (call core.svec %₉ %₁₀) +12 slot₂/T +13 (call core.svec %₁₂) +14 SourceLocation::1:10 +15 (call core.svec %₁₁ %₁₃ %₁₄) +16 --- method core.nothing %₁₅ slots: [slot₁/#self#(called) slot₂/x] 1 (call slot₁/#self# slot₂/x 1 2) 2 (return %₁) -16 TestMod.f -17 (call core.Typeof %₁₆) -18 slot₂/T -19 slot₁/S -20 (call core.svec %₁₇ %₁₈ %₁₉) -21 slot₂/T -22 slot₁/S -23 (call core.svec %₂₁ %₂₂) -24 SourceLocation::1:10 -25 (call core.svec %₂₀ %₂₃ %₂₄) -26 --- method core.nothing %₂₅ +17 (latestworld) +18 TestMod.f +19 (call core.Typeof %₁₈) +20 slot₂/T +21 slot₁/S +22 (call core.svec %₁₉ %₂₀ %₂₁) +23 slot₂/T +24 slot₁/S +25 (call core.svec %₂₃ %₂₄) +26 SourceLocation::1:10 +27 (call core.svec %₂₂ %₂₅ %₂₆) +28 --- method core.nothing %₂₇ slots: [slot₁/#self#(called) slot₂/x slot₃/y] 1 (call slot₁/#self# slot₂/x slot₃/y 2) 2 (return %₁) -27 TestMod.f -28 (call core.Typeof %₂₇) -29 slot₂/T -30 slot₁/S -31 slot₃/U -32 (call core.svec %₂₈ %₂₉ %₃₀ %₃₁) -33 slot₂/T -34 slot₁/S -35 slot₃/U -36 (call core.svec %₃₃ %₃₄ %₃₅) -37 SourceLocation::1:10 -38 (call core.svec %₃₂ %₃₆ %₃₇) -39 --- method core.nothing %₃₈ +29 (latestworld) +30 TestMod.f +31 (call core.Typeof %₃₀) +32 slot₂/T +33 slot₁/S +34 slot₃/U +35 (call core.svec %₃₁ %₃₂ %₃₃ %₃₄) +36 slot₂/T +37 slot₁/S +38 slot₃/U +39 (call core.svec %₃₆ %₃₇ %₃₈) +40 SourceLocation::1:10 +41 (call core.svec %₃₅ %₃₉ %₄₀) +42 --- method core.nothing %₄₁ slots: [slot₁/#self#(!read) slot₂/x slot₃/y slot₄/z] 1 (call core.tuple slot₂/x slot₃/y slot₄/z) 2 (return %₁) -40 TestMod.f -41 (return %₄₀) +43 (latestworld) +44 TestMod.f +45 (return %₄₄) ######################################## # Positional args and type parameters with transitive dependencies @@ -579,56 +618,57 @@ function f(x, y::S=[1], z::U=2) where {T, S<:AbstractVector{T}, U} end #--------------------- 1 (method TestMod.f) -2 (= slot₂/T (call core.TypeVar :T)) -3 TestMod.AbstractVector -4 slot₂/T -5 (call core.apply_type %₃ %₄) -6 (= slot₁/S (call core.TypeVar :S %₅)) -7 (= slot₃/U (call core.TypeVar :U)) -8 TestMod.f -9 (call core.Typeof %₈) -10 (call core.svec %₉ core.Any) -11 (call core.svec) -12 SourceLocation::1:10 -13 (call core.svec %₁₀ %₁₁ %₁₂) -14 --- method core.nothing %₁₃ +2 (latestworld) +3 (= slot₂/T (call core.TypeVar :T)) +4 TestMod.AbstractVector +5 slot₂/T +6 (call core.apply_type %₄ %₅) +7 (= slot₁/S (call core.TypeVar :S %₆)) +8 (= slot₃/U (call core.TypeVar :U)) +9 TestMod.f +10 (call core.Typeof %₉) +11 (call core.svec %₁₀ core.Any) +12 (call core.svec) +13 SourceLocation::1:10 +14 (call core.svec %₁₁ %₁₂ %₁₃) +15 --- method core.nothing %₁₄ slots: [slot₁/#self#(called) slot₂/x] 1 (call top.vect 1) 2 (call slot₁/#self# slot₂/x %₁ 2) 3 (return %₂) -15 TestMod.f -16 (call core.Typeof %₁₅) -17 slot₁/S -18 (call core.svec %₁₆ core.Any %₁₇) -19 slot₂/T -20 slot₁/S -21 (call core.svec %₁₉ %₂₀) -22 SourceLocation::1:10 -23 (call core.svec %₁₈ %₂₁ %₂₂) -24 --- method core.nothing %₂₃ +16 (latestworld) +17 TestMod.f +18 (call core.Typeof %₁₇) +19 slot₁/S +20 (call core.svec %₁₈ core.Any %₁₉) +21 slot₂/T +22 slot₁/S +23 (call core.svec %₂₁ %₂₂) +24 SourceLocation::1:10 +25 (call core.svec %₂₀ %₂₃ %₂₄) +26 --- method core.nothing %₂₅ slots: [slot₁/#self#(called) slot₂/x slot₃/y] 1 (call slot₁/#self# slot₂/x slot₃/y 2) 2 (return %₁) -25 TestMod.f -26 (call core.Typeof %₂₅) -27 slot₁/S -28 slot₃/U -29 (call core.svec %₂₆ core.Any %₂₇ %₂₈) -30 slot₂/T -31 slot₁/S -32 slot₃/U -33 (call core.svec %₃₀ %₃₁ %₃₂) -34 SourceLocation::1:10 -35 (call core.svec %₂₉ %₃₃ %₃₄) -36 --- method core.nothing %₃₅ +27 (latestworld) +28 TestMod.f +29 (call core.Typeof %₂₈) +30 slot₁/S +31 slot₃/U +32 (call core.svec %₂₉ core.Any %₃₀ %₃₁) +33 slot₂/T +34 slot₁/S +35 slot₃/U +36 (call core.svec %₃₃ %₃₄ %₃₅) +37 SourceLocation::1:10 +38 (call core.svec %₃₂ %₃₆ %₃₇) +39 --- method core.nothing %₃₈ slots: [slot₁/#self#(!read) slot₂/x slot₃/y slot₄/z] - 1 static_parameter₁ - 2 static_parameter₂ - 3 static_parameter₃ - 4 (call core.tuple slot₂/x slot₃/y slot₄/z %₁ %₂ %₃) - 5 (return %₄) -37 TestMod.f -38 (return %₃₇) + 1 (call core.tuple slot₂/x slot₃/y slot₄/z static_parameter₁ static_parameter₂ static_parameter₃) + 2 (return %₁) +40 (latestworld) +41 TestMod.f +42 (return %₄₁) ######################################## # Default positional args are allowed before trailing slurp with no default @@ -637,29 +677,32 @@ function f(x=1, ys...) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(called)] 1 (call slot₁/#self# 1) 2 (return %₁) -9 TestMod.f -10 (call core.Typeof %₉) -11 (call core.apply_type core.Vararg core.Any) -12 (call core.svec %₁₀ core.Any %₁₁) -13 (call core.svec) -14 SourceLocation::1:10 -15 (call core.svec %₁₂ %₁₃ %₁₄) -16 --- method core.nothing %₁₅ +10 (latestworld) +11 TestMod.f +12 (call core.Typeof %₁₁) +13 (call core.apply_type core.Vararg core.Any) +14 (call core.svec %₁₂ core.Any %₁₃) +15 (call core.svec) +16 SourceLocation::1:10 +17 (call core.svec %₁₄ %₁₅ %₁₆) +18 --- method core.nothing %₁₇ slots: [slot₁/#self#(!read) slot₂/x(!read) slot₃/ys] 1 slot₃/ys 2 (return %₁) -17 TestMod.f -18 (return %₁₇) +19 (latestworld) +20 TestMod.f +21 (return %₂₀) ######################################## # Error: Default positional args before non-default arg @@ -680,29 +723,32 @@ function f(xs...=1) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(called)] 1 (call slot₁/#self# 1) 2 (return %₁) -9 TestMod.f -10 (call core.Typeof %₉) -11 (call core.apply_type core.Vararg core.Any) -12 (call core.svec %₁₀ %₁₁) -13 (call core.svec) -14 SourceLocation::1:10 -15 (call core.svec %₁₂ %₁₃ %₁₄) -16 --- method core.nothing %₁₅ +10 (latestworld) +11 TestMod.f +12 (call core.Typeof %₁₁) +13 (call core.apply_type core.Vararg core.Any) +14 (call core.svec %₁₂ %₁₃) +15 (call core.svec) +16 SourceLocation::1:10 +17 (call core.svec %₁₄ %₁₅ %₁₆) +18 --- method core.nothing %₁₇ slots: [slot₁/#self#(!read) slot₂/xs] 1 slot₂/xs 2 (return %₁) -17 TestMod.f -18 (return %₁₇) +19 (latestworld) +20 TestMod.f +21 (return %₂₀) ######################################## # Positional arg with slurp and splatted default value @@ -711,30 +757,33 @@ function f(xs...=(1,2)...) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#] 1 (call core.tuple 1 2) 2 (call core._apply_iterate top.iterate slot₁/#self# %₁) 3 (return %₂) -9 TestMod.f -10 (call core.Typeof %₉) -11 (call core.apply_type core.Vararg core.Any) -12 (call core.svec %₁₀ %₁₁) -13 (call core.svec) -14 SourceLocation::1:10 -15 (call core.svec %₁₂ %₁₃ %₁₄) -16 --- method core.nothing %₁₅ +10 (latestworld) +11 TestMod.f +12 (call core.Typeof %₁₁) +13 (call core.apply_type core.Vararg core.Any) +14 (call core.svec %₁₂ %₁₃) +15 (call core.svec) +16 SourceLocation::1:10 +17 (call core.svec %₁₄ %₁₅ %₁₆) +18 --- method core.nothing %₁₇ slots: [slot₁/#self#(!read) slot₂/xs] 1 slot₂/xs 2 (return %₁) -17 TestMod.f -18 (return %₁₇) +19 (latestworld) +20 TestMod.f +21 (return %₂₀) ######################################## # Trivial function argument destructuring @@ -742,13 +791,14 @@ function f(x, (y,z), w) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃ core.Any core.Any core.Any) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄ core.Any core.Any core.Any) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read) slot₂/x(!read) slot₃/destructured_arg slot₄/w(!read) slot₅/iterstate slot₆/y(!read) slot₇/z(!read)] 1 (call top.indexed_iterate slot₃/destructured_arg 1) 2 (= slot₆/y (call core.getfield %₁ 1)) @@ -757,8 +807,9 @@ end 5 (call top.indexed_iterate slot₃/destructured_arg 2 %₄) 6 (= slot₇/z (call core.getfield %₅ 1)) 7 (return core.nothing) -9 TestMod.f -10 (return %₉) +10 (latestworld) +11 TestMod.f +12 (return %₁₁) ######################################## # Function argument destructuring combined with splats, types and and defaults @@ -766,32 +817,35 @@ function f((x,)::T...=rhs) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(called)] 1 TestMod.rhs 2 (call slot₁/#self# %₁) 3 (return %₂) -9 TestMod.f -10 (call core.Typeof %₉) -11 TestMod.T -12 (call core.apply_type core.Vararg %₁₁) -13 (call core.svec %₁₀ %₁₂) -14 (call core.svec) -15 SourceLocation::1:10 -16 (call core.svec %₁₃ %₁₄ %₁₅) -17 --- method core.nothing %₁₆ +10 (latestworld) +11 TestMod.f +12 (call core.Typeof %₁₁) +13 TestMod.T +14 (call core.apply_type core.Vararg %₁₃) +15 (call core.svec %₁₂ %₁₄) +16 (call core.svec) +17 SourceLocation::1:10 +18 (call core.svec %₁₅ %₁₆ %₁₇) +19 --- method core.nothing %₁₈ slots: [slot₁/#self#(!read) slot₂/destructured_arg slot₃/x(!read)] 1 (call top.indexed_iterate slot₂/destructured_arg 1) 2 (= slot₃/x (call core.getfield %₁ 1)) 3 (return core.nothing) -18 TestMod.f -19 (return %₁₈) +20 (latestworld) +21 TestMod.f +22 (return %₂₁) ######################################## # Function argument destructuring combined with splats, types and and defaults @@ -799,24 +853,26 @@ function f(x=default_x)::T end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(called)] 1 TestMod.default_x 2 (call slot₁/#self# %₁) 3 (return %₂) -9 TestMod.f -10 (call core.Typeof %₉) -11 (call core.svec %₁₀ core.Any) -12 (call core.svec) -13 SourceLocation::1:10 -14 (call core.svec %₁₁ %₁₂ %₁₃) -15 --- method core.nothing %₁₄ +10 (latestworld) +11 TestMod.f +12 (call core.Typeof %₁₁) +13 (call core.svec %₁₂ core.Any) +14 (call core.svec) +15 SourceLocation::1:10 +16 (call core.svec %₁₃ %₁₄ %₁₅) +17 --- method core.nothing %₁₆ slots: [slot₁/#self#(!read) slot₂/x(!read) slot₃/tmp(!read)] 1 TestMod.T 2 (= slot₃/tmp core.nothing) @@ -829,8 +885,9 @@ end 9 (= slot₃/tmp (call core.typeassert %₈ %₁)) 10 slot₃/tmp 11 (return %₁₀) -16 TestMod.f -17 (return %₁₆) +18 (latestworld) +19 TestMod.f +20 (return %₁₉) ######################################## # Duplicate destructured placeholders ok @@ -838,21 +895,23 @@ function f((_,), (_,)) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃ core.Any core.Any) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄ core.Any core.Any) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read) slot₂/destructured_arg slot₃/destructured_arg] 1 (call top.indexed_iterate slot₂/destructured_arg 1) 2 (call core.getfield %₁ 1) 3 (call top.indexed_iterate slot₃/destructured_arg 1) 4 (call core.getfield %₃ 1) 5 (return core.nothing) -9 TestMod.f -10 (return %₉) +10 (latestworld) +11 TestMod.f +12 (return %₁₁) ######################################## # Slot flags @@ -861,20 +920,22 @@ function f(@nospecialize(x), g, y) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃ core.Any core.Any core.Any) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄ core.Any core.Any core.Any) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read) slot₂/x(nospecialize,!read) slot₃/g(called) slot₄/y] 1 TestMod.+ 2 (call slot₃/g) 3 (call %₁ %₂ slot₄/y) 4 (return %₃) -9 TestMod.f -10 (return %₉) +10 (latestworld) +11 TestMod.f +12 (return %₁₁) ######################################## # Function return without arguments @@ -884,19 +945,21 @@ function f() end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read)] 1 (return core.nothing) 2 TestMod.after_return 3 (return %₂) -9 TestMod.f -10 (return %₉) +10 (latestworld) +11 TestMod.f +12 (return %₁₁) ######################################## # Binding docs to functions @@ -907,19 +970,21 @@ function f() end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃) -5 (call core.svec) -6 SourceLocation::4:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄) +6 (call core.svec) +7 SourceLocation::4:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read)] 1 (return core.nothing) -9 TestMod.f -10 (call JuliaLowering.bind_docs! %₉ "some docs\n" %₇) +10 (latestworld) 11 TestMod.f -12 (return %₁₁) +12 (call JuliaLowering.bind_docs! %₁₁ "some docs\n" %₈) +13 TestMod.f +14 (return %₁₃) ######################################## # Binding docs to callable type @@ -929,17 +994,19 @@ some docs function (x::T)() end #--------------------- -1 TestMod.T -2 (call core.svec %₁) -3 (call core.svec) -4 SourceLocation::4:10 -5 (call core.svec %₂ %₃ %₄) -6 --- method core.nothing %₅ +1 (latestworld) +2 TestMod.T +3 (call core.svec %₂) +4 (call core.svec) +5 SourceLocation::4:10 +6 (call core.svec %₃ %₄ %₅) +7 --- method core.nothing %₆ slots: [slot₁/x(!read)] 1 (return core.nothing) -7 TestMod.T -8 (call JuliaLowering.bind_docs! %₇ "some docs\n" %₅) -9 (return core.nothing) +8 (latestworld) +9 TestMod.T +10 (call JuliaLowering.bind_docs! %₉ "some docs\n" %₆) +11 (return core.nothing) ######################################## # Keyword function with defaults. @@ -957,56 +1024,60 @@ end #--------------------- 1 (method TestMod.f_kw_simple) 2 (method TestMod.#f_kw_simple#0) -3 TestMod.#f_kw_simple#0 -4 (call core.Typeof %₃) -5 TestMod.Char -6 TestMod.Bool -7 TestMod.f_kw_simple -8 (call core.Typeof %₇) -9 TestMod.Int -10 TestMod.Float64 -11 (call core.svec %₄ %₅ %₆ %₈ %₉ %₁₀) -12 (call core.svec) -13 SourceLocation::1:10 -14 (call core.svec %₁₁ %₁₂ %₁₃) -15 --- method core.nothing %₁₄ +3 (latestworld) +4 TestMod.#f_kw_simple#0 +5 (call core.Typeof %₄) +6 TestMod.Char +7 TestMod.Bool +8 TestMod.f_kw_simple +9 (call core.Typeof %₈) +10 TestMod.Int +11 TestMod.Float64 +12 (call core.svec %₅ %₆ %₇ %₉ %₁₀ %₁₁) +13 (call core.svec) +14 SourceLocation::1:10 +15 (call core.svec %₁₂ %₁₃ %₁₄) +16 --- method core.nothing %₁₅ slots: [slot₁/#self#(!read) slot₂/x slot₃/y slot₄/#self#(!read) slot₅/a slot₆/b] 1 (meta :nkw 2) 2 (call core.tuple slot₅/a slot₆/b slot₂/x slot₃/y) 3 (return %₂) -16 (call core.typeof core.kwcall) -17 TestMod.f_kw_simple -18 (call core.Typeof %₁₇) -19 (call core.svec %₁₆ core.NamedTuple %₁₈) -20 (call core.svec) -21 SourceLocation::1:10 -22 (call core.svec %₁₉ %₂₀ %₂₁) -23 --- method core.nothing %₂₂ +17 (latestworld) +18 (call core.typeof core.kwcall) +19 TestMod.f_kw_simple +20 (call core.Typeof %₁₉) +21 (call core.svec %₁₈ core.NamedTuple %₂₀) +22 (call core.svec) +23 SourceLocation::1:10 +24 (call core.svec %₂₁ %₂₂ %₂₃) +25 --- method core.nothing %₂₄ slots: [slot₁/#self#(called) slot₂/kws slot₃/#self#] 1 (call slot₁/#self# slot₂/kws slot₃/#self# 1 1.0) 2 (return %₁) -24 (call core.typeof core.kwcall) -25 TestMod.f_kw_simple -26 (call core.Typeof %₂₅) -27 TestMod.Int -28 (call core.svec %₂₄ core.NamedTuple %₂₆ %₂₇) -29 (call core.svec) -30 SourceLocation::1:10 -31 (call core.svec %₂₈ %₂₉ %₃₀) -32 --- method core.nothing %₃₁ +26 (latestworld) +27 (call core.typeof core.kwcall) +28 TestMod.f_kw_simple +29 (call core.Typeof %₂₈) +30 TestMod.Int +31 (call core.svec %₂₇ core.NamedTuple %₂₉ %₃₀) +32 (call core.svec) +33 SourceLocation::1:10 +34 (call core.svec %₃₁ %₃₂ %₃₃) +35 --- method core.nothing %₃₄ slots: [slot₁/#self#(called) slot₂/kws slot₃/#self# slot₄/a] 1 (call slot₁/#self# slot₂/kws slot₃/#self# slot₄/a 1.0) 2 (return %₁) -33 (call core.typeof core.kwcall) -34 TestMod.f_kw_simple -35 (call core.Typeof %₃₄) -36 TestMod.Int -37 TestMod.Float64 -38 (call core.svec %₃₃ core.NamedTuple %₃₅ %₃₆ %₃₇) -39 (call core.svec) -40 SourceLocation::1:10 -41 (call core.svec %₃₈ %₃₉ %₄₀) -42 --- method core.nothing %₄₁ +36 (latestworld) +37 (call core.typeof core.kwcall) +38 TestMod.f_kw_simple +39 (call core.Typeof %₃₈) +40 TestMod.Int +41 TestMod.Float64 +42 (call core.svec %₃₇ core.NamedTuple %₃₉ %₄₀ %₄₁) +43 (call core.svec) +44 SourceLocation::1:10 +45 (call core.svec %₄₂ %₄₃ %₄₄) +46 --- method core.nothing %₄₅ slots: [slot₁/#self#(!read) slot₂/kws slot₃/#self# slot₄/a slot₅/b slot₆/kwtmp slot₇/x(!read) slot₈/y(!read)] 1 (newvar slot₇/x) 2 (newvar slot₈/y) @@ -1048,42 +1119,47 @@ end 38 TestMod.#f_kw_simple#0 39 (call %₃₈ %₁₆ %₃₀ slot₃/#self# slot₄/a slot₅/b) 40 (return %₃₉) -43 TestMod.f_kw_simple -44 (call core.Typeof %₄₃) -45 (call core.svec %₄₄) -46 (call core.svec) -47 SourceLocation::1:10 -48 (call core.svec %₄₅ %₄₆ %₄₇) -49 --- method core.nothing %₄₈ +47 (latestworld) +48 (latestworld) +49 TestMod.f_kw_simple +50 (call core.Typeof %₄₉) +51 (call core.svec %₅₀) +52 (call core.svec) +53 SourceLocation::1:10 +54 (call core.svec %₅₁ %₅₂ %₅₃) +55 --- method core.nothing %₅₄ slots: [slot₁/#self#(called)] 1 (call slot₁/#self# 1 1.0) 2 (return %₁) -50 TestMod.f_kw_simple -51 (call core.Typeof %₅₀) -52 TestMod.Int -53 (call core.svec %₅₁ %₅₂) -54 (call core.svec) -55 SourceLocation::1:10 -56 (call core.svec %₅₃ %₅₄ %₅₅) -57 --- method core.nothing %₅₆ +56 (latestworld) +57 TestMod.f_kw_simple +58 (call core.Typeof %₅₇) +59 TestMod.Int +60 (call core.svec %₅₈ %₅₉) +61 (call core.svec) +62 SourceLocation::1:10 +63 (call core.svec %₆₀ %₆₁ %₆₂) +64 --- method core.nothing %₆₃ slots: [slot₁/#self#(called) slot₂/a] 1 (call slot₁/#self# slot₂/a 1.0) 2 (return %₁) -58 TestMod.f_kw_simple -59 (call core.Typeof %₅₈) -60 TestMod.Int -61 TestMod.Float64 -62 (call core.svec %₅₉ %₆₀ %₆₁) -63 (call core.svec) -64 SourceLocation::1:10 -65 (call core.svec %₆₂ %₆₃ %₆₄) -66 --- method core.nothing %₆₅ +65 (latestworld) +66 TestMod.f_kw_simple +67 (call core.Typeof %₆₆) +68 TestMod.Int +69 TestMod.Float64 +70 (call core.svec %₆₇ %₆₈ %₆₉) +71 (call core.svec) +72 SourceLocation::1:10 +73 (call core.svec %₇₀ %₇₁ %₇₂) +74 --- method core.nothing %₇₃ slots: [slot₁/#self# slot₂/a slot₃/b] 1 TestMod.#f_kw_simple#0 2 (call %₁ 'a' true slot₁/#self# slot₂/a slot₃/b) 3 (return %₂) -67 TestMod.f_kw_simple -68 (return %₆₇) +75 (latestworld) +76 TestMod.f_kw_simple +77 (return %₇₆) ######################################## # Keyword slurping - simple forwarding of all kws @@ -1093,49 +1169,54 @@ end #--------------------- 1 (method TestMod.f_kw_slurp_simple) 2 (method TestMod.#f_kw_slurp_simple#0) -3 TestMod.#f_kw_slurp_simple#0 -4 (call core.Typeof %₃) -5 (call top.pairs core.NamedTuple) -6 TestMod.f_kw_slurp_simple -7 (call core.Typeof %₆) -8 (call core.svec %₄ %₅ %₇) -9 (call core.svec) -10 SourceLocation::1:10 -11 (call core.svec %₈ %₉ %₁₀) -12 --- method core.nothing %₁₁ +3 (latestworld) +4 TestMod.#f_kw_slurp_simple#0 +5 (call core.Typeof %₄) +6 (call top.pairs core.NamedTuple) +7 TestMod.f_kw_slurp_simple +8 (call core.Typeof %₇) +9 (call core.svec %₅ %₆ %₈) +10 (call core.svec) +11 SourceLocation::1:10 +12 (call core.svec %₉ %₁₀ %₁₁) +13 --- method core.nothing %₁₂ slots: [slot₁/#self#(!read) slot₂/all_kws slot₃/#self#(!read)] 1 (meta :nkw 1) 2 slot₂/all_kws 3 (return %₂) -13 (call core.typeof core.kwcall) -14 TestMod.f_kw_slurp_simple -15 (call core.Typeof %₁₄) -16 (call core.svec %₁₃ core.NamedTuple %₁₅) -17 (call core.svec) -18 SourceLocation::1:10 -19 (call core.svec %₁₆ %₁₇ %₁₈) -20 --- method core.nothing %₁₉ +14 (latestworld) +15 (call core.typeof core.kwcall) +16 TestMod.f_kw_slurp_simple +17 (call core.Typeof %₁₆) +18 (call core.svec %₁₅ core.NamedTuple %₁₇) +19 (call core.svec) +20 SourceLocation::1:10 +21 (call core.svec %₁₈ %₁₉ %₂₀) +22 --- method core.nothing %₂₁ slots: [slot₁/#self#(!read) slot₂/kws slot₃/#self# slot₄/all_kws(!read)] 1 (newvar slot₄/all_kws) 2 (call top.pairs slot₂/kws) 3 TestMod.#f_kw_slurp_simple#0 4 (call %₃ %₂ slot₃/#self#) 5 (return %₄) -21 TestMod.f_kw_slurp_simple -22 (call core.Typeof %₂₁) -23 (call core.svec %₂₂) -24 (call core.svec) -25 SourceLocation::1:10 -26 (call core.svec %₂₃ %₂₄ %₂₅) -27 --- method core.nothing %₂₆ +23 (latestworld) +24 (latestworld) +25 TestMod.f_kw_slurp_simple +26 (call core.Typeof %₂₅) +27 (call core.svec %₂₆) +28 (call core.svec) +29 SourceLocation::1:10 +30 (call core.svec %₂₇ %₂₈ %₂₉) +31 --- method core.nothing %₃₀ slots: [slot₁/#self#] 1 TestMod.#f_kw_slurp_simple#0 2 (call core.NamedTuple) 3 (call top.pairs %₂) 4 (call %₁ %₃ slot₁/#self#) 5 (return %₄) -28 TestMod.f_kw_slurp_simple -29 (return %₂₈) +32 (latestworld) +33 TestMod.f_kw_slurp_simple +34 (return %₃₃) ######################################## # Keyword slurping @@ -1145,28 +1226,30 @@ end #--------------------- 1 (method TestMod.f_kw_slurp) 2 (method TestMod.#f_kw_slurp#0) -3 TestMod.#f_kw_slurp#0 -4 (call core.Typeof %₃) -5 (call top.pairs core.NamedTuple) -6 TestMod.f_kw_slurp -7 (call core.Typeof %₆) -8 (call core.svec %₄ core.Any %₅ %₇) -9 (call core.svec) -10 SourceLocation::1:10 -11 (call core.svec %₈ %₉ %₁₀) -12 --- method core.nothing %₁₁ +3 (latestworld) +4 TestMod.#f_kw_slurp#0 +5 (call core.Typeof %₄) +6 (call top.pairs core.NamedTuple) +7 TestMod.f_kw_slurp +8 (call core.Typeof %₇) +9 (call core.svec %₅ core.Any %₆ %₈) +10 (call core.svec) +11 SourceLocation::1:10 +12 (call core.svec %₉ %₁₀ %₁₁) +13 --- method core.nothing %₁₂ slots: [slot₁/#self#(!read) slot₂/x(!read) slot₃/non_x_kws(!read) slot₄/#self#(!read)] 1 (meta :nkw 2) 2 TestMod.all_kws 3 (return %₂) -13 (call core.typeof core.kwcall) -14 TestMod.f_kw_slurp -15 (call core.Typeof %₁₄) -16 (call core.svec %₁₃ core.NamedTuple %₁₅) -17 (call core.svec) -18 SourceLocation::1:10 -19 (call core.svec %₁₆ %₁₇ %₁₈) -20 --- method core.nothing %₁₉ +14 (latestworld) +15 (call core.typeof core.kwcall) +16 TestMod.f_kw_slurp +17 (call core.Typeof %₁₆) +18 (call core.svec %₁₅ core.NamedTuple %₁₇) +19 (call core.svec) +20 SourceLocation::1:10 +21 (call core.svec %₁₈ %₁₉ %₂₀) +22 --- method core.nothing %₂₁ slots: [slot₁/#self#(!read) slot₂/kws slot₃/#self# slot₄/kwtmp slot₅/non_x_kws(!read) slot₆/x(!read)] 1 (newvar slot₅/non_x_kws) 2 (newvar slot₆/x) @@ -1185,13 +1268,15 @@ end 15 TestMod.#f_kw_slurp#0 16 (call %₁₅ %₁₀ %₁₄ slot₃/#self#) 17 (return %₁₆) -21 TestMod.f_kw_slurp -22 (call core.Typeof %₂₁) -23 (call core.svec %₂₂) -24 (call core.svec) -25 SourceLocation::1:10 -26 (call core.svec %₂₃ %₂₄ %₂₅) -27 --- method core.nothing %₂₆ +23 (latestworld) +24 (latestworld) +25 TestMod.f_kw_slurp +26 (call core.Typeof %₂₅) +27 (call core.svec %₂₆) +28 (call core.svec) +29 SourceLocation::1:10 +30 (call core.svec %₂₇ %₂₈ %₂₉) +31 --- method core.nothing %₃₀ slots: [slot₁/#self#] 1 TestMod.#f_kw_slurp#0 2 TestMod.x_default @@ -1199,8 +1284,9 @@ end 4 (call top.pairs %₃) 5 (call %₁ %₂ %₄ slot₁/#self#) 6 (return %₅) -28 TestMod.f_kw_slurp -29 (return %₂₈) +32 (latestworld) +33 TestMod.f_kw_slurp +34 (return %₃₃) ######################################## # Static parameters used in keywords, with and without the static parameter @@ -1214,40 +1300,40 @@ end #--------------------- 1 (method TestMod.f_kw_sparams) 2 (method TestMod.#f_kw_sparams#0) -3 (= slot₂/X (call core.TypeVar :X)) -4 (= slot₁/A (call core.TypeVar :A)) -5 TestMod.#f_kw_sparams#0 -6 (call core.Typeof %₅) -7 slot₁/A -8 slot₂/X -9 TestMod.f_kw_sparams -10 (call core.Typeof %₉) -11 slot₂/X -12 (call core.svec %₆ %₇ %₈ %₁₀ %₁₁) -13 slot₂/X -14 slot₁/A -15 (call core.svec %₁₃ %₁₄) -16 SourceLocation::1:10 -17 (call core.svec %₁₂ %₁₅ %₁₆) -18 --- method core.nothing %₁₇ +3 (latestworld) +4 (= slot₂/X (call core.TypeVar :X)) +5 (= slot₁/A (call core.TypeVar :A)) +6 TestMod.#f_kw_sparams#0 +7 (call core.Typeof %₆) +8 slot₁/A +9 slot₂/X +10 TestMod.f_kw_sparams +11 (call core.Typeof %₁₀) +12 slot₂/X +13 (call core.svec %₇ %₈ %₉ %₁₁ %₁₂) +14 slot₂/X +15 slot₁/A +16 (call core.svec %₁₄ %₁₅) +17 SourceLocation::1:10 +18 (call core.svec %₁₃ %₁₆ %₁₇) +19 --- method core.nothing %₁₈ slots: [slot₁/#self#(!read) slot₂/a(!read) slot₃/b(!read) slot₄/#self#(!read) slot₅/x(!read)] 1 (meta :nkw 2) - 2 static_parameter₁ - 3 static_parameter₂ - 4 (call core.tuple %₂ %₃) - 5 (return %₄) -19 (= slot₄/X (call core.TypeVar :X)) -20 (= slot₃/A (call core.TypeVar :A)) -21 (call core.typeof core.kwcall) -22 TestMod.f_kw_sparams -23 (call core.Typeof %₂₂) -24 slot₄/X -25 (call core.svec %₂₁ core.NamedTuple %₂₃ %₂₄) + 2 (call core.tuple static_parameter₁ static_parameter₂) + 3 (return %₂) +20 (latestworld) +21 (= slot₄/X (call core.TypeVar :X)) +22 (= slot₃/A (call core.TypeVar :A)) +23 (call core.typeof core.kwcall) +24 TestMod.f_kw_sparams +25 (call core.Typeof %₂₄) 26 slot₄/X -27 (call core.svec %₂₆) -28 SourceLocation::1:10 -29 (call core.svec %₂₅ %₂₇ %₂₈) -30 --- method core.nothing %₂₉ +27 (call core.svec %₂₃ core.NamedTuple %₂₅ %₂₆) +28 slot₄/X +29 (call core.svec %₂₈) +30 SourceLocation::1:10 +31 (call core.svec %₂₇ %₂₉ %₃₀) +32 --- method core.nothing %₃₁ slots: [slot₁/#self#(!read) slot₂/kws slot₃/#self# slot₄/x slot₅/kwtmp slot₆/a(!read) slot₇/b(!read)] 1 (newvar slot₆/a) 2 (newvar slot₇/b) @@ -1260,49 +1346,50 @@ end 9 (= slot₅/kwtmp %₈) 10 slot₅/kwtmp 11 (call core.isdefined slot₂/kws :b) - 12 (gotoifnot %₁₁ label₂₃) + 12 (gotoifnot %₁₁ label₂₁) 13 (call core.getfield slot₂/kws :b) - 14 static_parameter₁ - 15 (call core.isa %₁₃ %₁₄) - 16 (gotoifnot %₁₅ label₁₈) - 17 (goto label₂₁) - 18 static_parameter₁ - 19 (new core.TypeError :keyword argument :b %₁₈ %₁₃) - 20 (call core.throw %₁₉) - 21 (= slot₅/kwtmp %₁₃) - 22 (goto label₂₅) - 23 TestMod.b_def - 24 (= slot₅/kwtmp %₂₃) - 25 slot₅/kwtmp - 26 (call top.keys slot₂/kws) - 27 (call core.tuple :a :b) - 28 (call top.diff_names %₂₆ %₂₇) - 29 (call top.isempty %₂₈) - 30 (gotoifnot %₂₉ label₃₂) - 31 (goto label₃₃) - 32 (call top.kwerr slot₂/kws slot₃/#self# slot₄/x) - 33 TestMod.#f_kw_sparams#0 - 34 (call %₃₃ %₁₀ %₂₅ slot₃/#self# slot₄/x) - 35 (return %₃₄) -31 (= slot₆/X (call core.TypeVar :X)) -32 (= slot₅/A (call core.TypeVar :A)) -33 TestMod.f_kw_sparams -34 (call core.Typeof %₃₃) -35 slot₆/X -36 (call core.svec %₃₄ %₃₅) -37 slot₆/X -38 (call core.svec %₃₇) -39 SourceLocation::1:10 -40 (call core.svec %₃₆ %₃₈ %₃₉) -41 --- method core.nothing %₄₀ + 14 (call core.isa %₁₃ static_parameter₁) + 15 (gotoifnot %₁₄ label₁₇) + 16 (goto label₁₉) + 17 (new core.TypeError :keyword argument :b static_parameter₁ %₁₃) + 18 (call core.throw %₁₇) + 19 (= slot₅/kwtmp %₁₃) + 20 (goto label₂₃) + 21 TestMod.b_def + 22 (= slot₅/kwtmp %₂₁) + 23 slot₅/kwtmp + 24 (call top.keys slot₂/kws) + 25 (call core.tuple :a :b) + 26 (call top.diff_names %₂₄ %₂₅) + 27 (call top.isempty %₂₆) + 28 (gotoifnot %₂₇ label₃₀) + 29 (goto label₃₁) + 30 (call top.kwerr slot₂/kws slot₃/#self# slot₄/x) + 31 TestMod.#f_kw_sparams#0 + 32 (call %₃₁ %₁₀ %₂₃ slot₃/#self# slot₄/x) + 33 (return %₃₂) +33 (latestworld) +34 (latestworld) +35 (= slot₆/X (call core.TypeVar :X)) +36 (= slot₅/A (call core.TypeVar :A)) +37 TestMod.f_kw_sparams +38 (call core.Typeof %₃₇) +39 slot₆/X +40 (call core.svec %₃₈ %₃₉) +41 slot₆/X +42 (call core.svec %₄₁) +43 SourceLocation::1:10 +44 (call core.svec %₄₀ %₄₂ %₄₃) +45 --- method core.nothing %₄₄ slots: [slot₁/#self# slot₂/x] 1 TestMod.#f_kw_sparams#0 2 TestMod.a_def 3 TestMod.b_def 4 (call %₁ %₂ %₃ slot₁/#self# slot₂/x) 5 (return %₄) -42 TestMod.f_kw_sparams -43 (return %₄₂) +46 (latestworld) +47 TestMod.f_kw_sparams +48 (return %₄₇) ######################################## # Error: Static parameter which is unused in keyword body arg types @@ -1364,30 +1451,35 @@ end #--------------------- 1 (method TestMod.f_only_generated) 2 (method TestMod.#f_only_generated@generator#0) -3 TestMod.#f_only_generated@generator#0 -4 (call core.Typeof %₃) -5 (call core.svec %₄ JuliaLowering.MacroContext core.Any core.Any core.Any) -6 (call core.svec) -7 SourceLocation::1:21 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +3 (latestworld) +4 (latestworld) +5 TestMod.#f_only_generated@generator#0 +6 (call core.Typeof %₅) +7 (call core.svec %₆ JuliaLowering.MacroContext core.Any core.Any core.Any) +8 (call core.svec) +9 SourceLocation::1:21 +10 (call core.svec %₇ %₈ %₉) +11 --- method core.nothing %₁₀ slots: [slot₁/#self#(!read) slot₂/__context__(!read) slot₃/#self#(!read) slot₄/x(nospecialize) slot₅/y(nospecialize)] 1 TestMod.generator_code 2 (call %₁ slot₄/x slot₅/y) 3 (return %₂) -10 TestMod.f_only_generated -11 (call core.Typeof %₁₀) -12 (call core.svec %₁₁ core.Any core.Any) -13 (call core.svec) -14 SourceLocation::1:21 -15 (call core.svec %₁₂ %₁₃ %₁₄) -16 --- method core.nothing %₁₅ +12 (latestworld) +13 (latestworld) +14 TestMod.f_only_generated +15 (call core.Typeof %₁₄) +16 (call core.svec %₁₅ core.Any core.Any) +17 (call core.svec) +18 SourceLocation::1:21 +19 (call core.svec %₁₆ %₁₇ %₁₈) +20 --- method core.nothing %₁₉ slots: [slot₁/#self#(!read) slot₂/x(!read) slot₃/y(!read)] 1 (meta :generated (new JuliaLowering.GeneratedFunctionStub TestMod.#f_only_generated@generator#0 SourceRef(SourceFile("@generated function f_only_generated(x, y)\n generator_code(x,y)\nend", 0, nothing, 1, [1, 44, 68, 71]), 1, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"macrocall", 0x0000), 0x00000046, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"@", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"MacroName", 0x0000), 0x00000009, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"function", 0x0000), 0x0000003b, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"function", 0x0001), 0x00000008, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0000), 0x00000016, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000010, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0000), 0x00000019, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0000), 0x00000013, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000e, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"end", 0x0001), 0x00000003, nothing)])])) (call core.svec :#self# :x :y) (call core.svec))) 2 (meta :generated_only) 3 (return core.nothing) -17 TestMod.f_only_generated -18 (return %₁₇) +21 (latestworld) +22 TestMod.f_only_generated +23 (return %₂₂) ######################################## # Partially generated function with `if @generated` @@ -1405,25 +1497,29 @@ end #--------------------- 1 (method TestMod.f_partially_generated) 2 (method TestMod.#f_partially_generated@generator#0) -3 TestMod.#f_partially_generated@generator#0 -4 (call core.Typeof %₃) -5 (call core.svec %₄ JuliaLowering.MacroContext core.Any core.Any core.Any) -6 (call core.svec) -7 SourceLocation::1:10 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +3 (latestworld) +4 (latestworld) +5 TestMod.#f_partially_generated@generator#0 +6 (call core.Typeof %₅) +7 (call core.svec %₆ JuliaLowering.MacroContext core.Any core.Any core.Any) +8 (call core.svec) +9 SourceLocation::1:10 +10 (call core.svec %₇ %₈ %₉) +11 --- method core.nothing %₁₀ slots: [slot₁/#self#(!read) slot₂/__context__(!read) slot₃/#self#(!read) slot₄/x(nospecialize,!read) slot₅/y(nospecialize,!read)] 1 (call JuliaLowering.interpolate_ast (inert (block (= maybe_gen_stuff (call some_gen_stuff x y))))) 2 (call core.tuple %₁) 3 (call JuliaLowering.interpolate_ast (inert (block (block (= nongen_stuff (call bothgen x y)) ($ (block (call JuliaLowering.interpolate_ast (inert (block (= maybe_gen_stuff (call some_gen_stuff x y))))))) (tuple-p nongen_stuff maybe_gen_stuff)))) %₂) 4 (return %₃) -10 TestMod.f_partially_generated -11 (call core.Typeof %₁₀) -12 (call core.svec %₁₁ core.Any core.Any) -13 (call core.svec) -14 SourceLocation::1:10 -15 (call core.svec %₁₂ %₁₃ %₁₄) -16 --- method core.nothing %₁₅ +12 (latestworld) +13 (latestworld) +14 TestMod.f_partially_generated +15 (call core.Typeof %₁₄) +16 (call core.svec %₁₅ core.Any core.Any) +17 (call core.svec) +18 SourceLocation::1:10 +19 (call core.svec %₁₆ %₁₇ %₁₈) +20 --- method core.nothing %₁₉ slots: [slot₁/#self#(!read) slot₂/x slot₃/y slot₄/maybe_gen_stuff slot₅/nongen_stuff] 1 (meta :generated (new JuliaLowering.GeneratedFunctionStub TestMod.#f_partially_generated@generator#0 SourceRef(SourceFile("function f_partially_generated(x, y)\n nongen_stuff = bothgen(x, y)\n if @generated\n quote\n maybe_gen_stuff = some_gen_stuff(x, y)\n end\n else\n maybe_gen_stuff = some_nongen_stuff(x, y)\n end\n (nongen_stuff, maybe_gen_stuff)\nend", 0, nothing, 1, [1, 38, 71, 89, 103, 154, 166, 175, 225, 233, 269, 272]), 1, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"function", 0x0000), 0x0000010f, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"function", 0x0001), 0x00000008, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0000), 0x0000001b, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000015, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0000), 0x000000e8, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0000), 0x0000001c, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000c, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0000), 0x0000000d, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000007, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)])]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"if", 0x0000), 0x0000009d, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"if", 0x0001), 0x00000002, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"macrocall", 0x0000), 0x0000000a, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"@", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"MacroName", 0x0000), 0x00000009, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0000), 0x00000052, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000009, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"quote", 0x0000), 0x00000044, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0000), 0x00000044, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"quote", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x0000000d, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0000), 0x00000026, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000f, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0000), 0x00000014, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000e, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)])]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000009, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"end", 0x0001), 0x00000003, nothing)])]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"else", 0x0001), 0x00000004, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0000), 0x00000037, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000009, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0000), 0x00000029, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000f, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0000), 0x00000017, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000011, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)])]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"end", 0x0001), 0x00000003, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"tuple", 0x0020), 0x0000001f, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000c, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000f, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"end", 0x0001), 0x00000003, nothing)])) (call core.svec :#self# :x :y) (call core.svec))) 2 TestMod.bothgen @@ -1434,6 +1530,7 @@ end 7 slot₄/maybe_gen_stuff 8 (call core.tuple %₆ %₇) 9 (return %₈) -17 TestMod.f_partially_generated -18 (return %₁₇) +21 (latestworld) +22 TestMod.f_partially_generated +23 (return %₂₂) diff --git a/test/generators_ir.jl b/test/generators_ir.jl index 22b2a3ab..0fb9ddf2 100644 --- a/test/generators_ir.jl +++ b/test/generators_ir.jl @@ -5,21 +5,25 @@ 1 (call core.svec) 2 (call core.svec) 3 (call JuliaLowering.eval_closure_type TestMod :#->##0 %₁ %₂) -4 TestMod.#->##0 -5 (call core.svec %₄ core.Any) -6 (call core.svec) -7 SourceLocation::1:2 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +4 (latestworld) +5 TestMod.#->##0 +6 (call core.svec %₅ core.Any) +7 (call core.svec) +8 SourceLocation::1:2 +9 (call core.svec %₆ %₇ %₈) +10 --- method core.nothing %₉ slots: [slot₁/#self#(!read) slot₂/x] 1 TestMod.+ 2 (call %₁ slot₂/x 1) 3 (return %₂) -10 TestMod.#->##0 -11 (new %₁₀) -12 TestMod.xs -13 (call top.Generator %₁₁ %₁₂) -14 (return %₁₃) +11 (latestworld) +12 (latestworld) +13 TestMod.#->##0 +14 (new %₁₃) +15 (latestworld) +16 TestMod.xs +17 (call top.Generator %₁₄ %₁₆) +18 (return %₁₇) ######################################## # Product iteration @@ -28,12 +32,13 @@ 1 (call core.svec) 2 (call core.svec) 3 (call JuliaLowering.eval_closure_type TestMod :#->##1 %₁ %₂) -4 TestMod.#->##1 -5 (call core.svec %₄ core.Any) -6 (call core.svec) -7 SourceLocation::1:2 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +4 (latestworld) +5 TestMod.#->##1 +6 (call core.svec %₅ core.Any) +7 (call core.svec) +8 SourceLocation::1:2 +9 (call core.svec %₆ %₇ %₈) +10 --- method core.nothing %₉ slots: [slot₁/#self#(!read) slot₂/destructured_arg slot₃/iterstate slot₄/x slot₅/y] 1 (call top.indexed_iterate slot₂/destructured_arg 1) 2 (= slot₄/x (call core.getfield %₁ 1)) @@ -46,13 +51,16 @@ 9 slot₅/y 10 (call %₇ %₈ %₉) 11 (return %₁₀) -10 TestMod.#->##1 -11 (new %₁₀) -12 TestMod.xs -13 TestMod.ys -14 (call top.product %₁₂ %₁₃) -15 (call top.Generator %₁₁ %₁₄) -16 (return %₁₅) +11 (latestworld) +12 (latestworld) +13 TestMod.#->##1 +14 (new %₁₃) +15 (latestworld) +16 TestMod.xs +17 TestMod.ys +18 (call top.product %₁₆ %₁₇) +19 (call top.Generator %₁₄ %₁₈) +20 (return %₁₉) ######################################## # Use `identity` as the Generator function when possible eg in filters @@ -61,12 +69,13 @@ 1 (call core.svec) 2 (call core.svec) 3 (call JuliaLowering.eval_closure_type TestMod :#->##2 %₁ %₂) -4 TestMod.#->##2 -5 (call core.svec %₄ core.Any) -6 (call core.svec) -7 SourceLocation::1:29 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +4 (latestworld) +5 TestMod.#->##2 +6 (call core.svec %₅ core.Any) +7 (call core.svec) +8 SourceLocation::1:29 +9 (call core.svec %₆ %₇ %₈) +10 --- method core.nothing %₉ slots: [slot₁/#self#(!read) slot₂/destructured_arg slot₃/iterstate slot₄/x slot₅/y(!read)] 1 (call top.indexed_iterate slot₂/destructured_arg 1) 2 (= slot₄/x (call core.getfield %₁ 1)) @@ -78,12 +87,15 @@ 8 slot₄/x 9 (call %₇ %₈) 10 (return %₉) -10 TestMod.#->##2 -11 (new %₁₀) -12 TestMod.iter -13 (call top.Filter %₁₁ %₁₂) -14 (call top.Generator top.identity %₁₃) -15 (return %₁₄) +11 (latestworld) +12 (latestworld) +13 TestMod.#->##2 +14 (new %₁₃) +15 (latestworld) +16 TestMod.iter +17 (call top.Filter %₁₄ %₁₆) +18 (call top.Generator top.identity %₁₇) +19 (return %₁₈) ######################################## # Use of placeholders in iteration vars @@ -92,19 +104,23 @@ 1 (call core.svec) 2 (call core.svec) 3 (call JuliaLowering.eval_closure_type TestMod :#->##3 %₁ %₂) -4 TestMod.#->##3 -5 (call core.svec %₄ core.Any) -6 (call core.svec) -7 SourceLocation::1:2 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +4 (latestworld) +5 TestMod.#->##3 +6 (call core.svec %₅ core.Any) +7 (call core.svec) +8 SourceLocation::1:2 +9 (call core.svec %₆ %₇ %₈) +10 --- method core.nothing %₉ slots: [slot₁/#self#(!read) slot₂/_(!read)] 1 (return 1) -10 TestMod.#->##3 -11 (new %₁₀) -12 TestMod.xs -13 (call top.Generator %₁₁ %₁₂) -14 (return %₁₃) +11 (latestworld) +12 (latestworld) +13 TestMod.#->##3 +14 (new %₁₃) +15 (latestworld) +16 TestMod.xs +17 (call top.Generator %₁₄ %₁₆) +18 (return %₁₇) ######################################## # Error: Use of placeholders in body @@ -121,12 +137,13 @@ LoweringError: 1 (call core.svec) 2 (call core.svec) 3 (call JuliaLowering.eval_closure_type TestMod :#->##5 %₁ %₂) -4 TestMod.#->##5 -5 (call core.svec %₄ core.Any) -6 (call core.svec) -7 SourceLocation::1:2 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +4 (latestworld) +5 TestMod.#->##5 +6 (call core.svec %₅ core.Any) +7 (call core.svec) +8 SourceLocation::1:2 +9 (call core.svec %₆ %₇ %₈) +10 --- method core.nothing %₉ slots: [slot₁/#self#(!read) slot₂/destructured_arg slot₃/iterstate slot₄/x(!read) slot₅/y(!read)] 1 (call top.indexed_iterate slot₂/destructured_arg 1) 2 (= slot₄/x (call core.getfield %₁ 1)) @@ -140,11 +157,14 @@ LoweringError: 10 (= slot₅/y (call core.getfield %₉ 1)) 11 TestMod.body 12 (return %₁₁) -10 TestMod.#->##5 -11 (new %₁₀) -12 TestMod.iter -13 (call top.Generator %₁₁ %₁₂) -14 (return %₁₃) +11 (latestworld) +12 (latestworld) +13 TestMod.#->##5 +14 (new %₁₃) +15 (latestworld) +16 TestMod.iter +17 (call top.Generator %₁₄ %₁₆) +18 (return %₁₇) ######################################## # return permitted in quoted syntax in generator @@ -153,20 +173,24 @@ LoweringError: 1 (call core.svec) 2 (call core.svec) 3 (call JuliaLowering.eval_closure_type TestMod :#->##6 %₁ %₂) -4 TestMod.#->##6 -5 (call core.svec %₄ core.Any) -6 (call core.svec) -7 SourceLocation::1:4 -8 (call core.svec %₅ %₆ %₇) -9 --- method core.nothing %₈ +4 (latestworld) +5 TestMod.#->##6 +6 (call core.svec %₅ core.Any) +7 (call core.svec) +8 SourceLocation::1:4 +9 (call core.svec %₆ %₇ %₈) +10 --- method core.nothing %₉ slots: [slot₁/#self#(!read) slot₂/_(!read)] 1 (call JuliaLowering.interpolate_ast (inert (return x))) 2 (return %₁) -10 TestMod.#->##6 -11 (new %₁₀) -12 TestMod.iter -13 (call top.Generator %₁₁ %₁₂) -14 (return %₁₃) +11 (latestworld) +12 (latestworld) +13 TestMod.#->##6 +14 (new %₁₃) +15 (latestworld) +16 TestMod.iter +17 (call top.Generator %₁₄ %₁₆) +18 (return %₁₇) ######################################## # Error: `return` not permitted in generator body @@ -183,26 +207,29 @@ LoweringError: 1 (call core.svec) 2 (call core.svec) 3 (call JuliaLowering.eval_closure_type TestMod :#->##7 %₁ %₂) -4 (call core.svec) +4 (latestworld) 5 (call core.svec) -6 (call JuliaLowering.eval_closure_type TestMod :#->#->##0 %₄ %₅) -7 TestMod.#->#->##0 -8 (call core.svec %₇ core.Any) -9 (call core.svec) -10 SourceLocation::1:2 -11 (call core.svec %₈ %₉ %₁₀) -12 --- method core.nothing %₁₁ +6 (call core.svec) +7 (call JuliaLowering.eval_closure_type TestMod :#->#->##0 %₅ %₆) +8 (latestworld) +9 TestMod.#->#->##0 +10 (call core.svec %₉ core.Any) +11 (call core.svec) +12 SourceLocation::1:2 +13 (call core.svec %₁₀ %₁₁ %₁₂) +14 --- method core.nothing %₁₃ slots: [slot₁/#self#(!read) slot₂/x slot₃/x] 1 slot₂/x 2 (= slot₃/x %₁) 3 slot₃/x 4 (return %₃) -13 TestMod.#->##7 -14 (call core.svec %₁₃ core.Any) -15 (call core.svec) -16 SourceLocation::1:2 -17 (call core.svec %₁₄ %₁₅ %₁₆) -18 --- method core.nothing %₁₇ +15 (latestworld) +16 TestMod.#->##7 +17 (call core.svec %₁₆ core.Any) +18 (call core.svec) +19 SourceLocation::1:2 +20 (call core.svec %₁₇ %₁₈ %₁₉) +21 --- method core.nothing %₂₀ slots: [slot₁/#self#(!read) slot₂/x(!read)] 1 TestMod.#->#->##0 2 (new %₁) @@ -210,13 +237,16 @@ LoweringError: 4 (call %₃ 1 2) 5 (call top.Generator %₂ %₄) 6 (return %₅) -19 TestMod.#->##7 -20 (new %₁₉) -21 TestMod.: -22 (call %₂₁ 1 3) -23 (call top.Generator %₂₀ %₂₂) -24 (call top.Flatten %₂₃) -25 (return %₂₄) +22 (latestworld) +23 (latestworld) +24 TestMod.#->##7 +25 (new %₂₄) +26 (latestworld) +27 TestMod.: +28 (call %₂₇ 1 3) +29 (call top.Generator %₂₅ %₂₈) +30 (call top.Flatten %₂₉) +31 (return %₃₀) ######################################## # Comprehension lowers to generator with collect diff --git a/test/macros_ir.jl b/test/macros_ir.jl index e1c6460c..792b7499 100644 --- a/test/macros_ir.jl +++ b/test/macros_ir.jl @@ -25,19 +25,21 @@ macro add_one(ex) end #--------------------- 1 (method TestMod.@add_one) -2 TestMod.@add_one -3 (call core.Typeof %₂) -4 (call core.svec %₃ JuliaLowering.MacroContext core.Any) -5 (call core.svec) -6 SourceLocation::1:7 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.@add_one +4 (call core.Typeof %₃) +5 (call core.svec %₄ JuliaLowering.MacroContext core.Any) +6 (call core.svec) +7 SourceLocation::1:7 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read) slot₂/__context__(!read) slot₃/ex] 1 (call core.tuple slot₃/ex) 2 (call JuliaLowering.interpolate_ast (inert (block (call-i ($ ex) + 1))) %₁) 3 (return %₂) -9 TestMod.@add_one -10 (return %₉) +10 (latestworld) +11 TestMod.@add_one +12 (return %₁₁) ######################################## # Macro using `__context__` @@ -46,19 +48,21 @@ macro foo(ex) end #--------------------- 1 (method TestMod.@foo) -2 TestMod.@foo -3 (call core.Typeof %₂) -4 (call core.svec %₃ JuliaLowering.MacroContext core.Any) -5 (call core.svec) -6 SourceLocation::1:7 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.@foo +4 (call core.Typeof %₃) +5 (call core.svec %₄ JuliaLowering.MacroContext core.Any) +6 (call core.svec) +7 SourceLocation::1:7 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read) slot₂/__context__ slot₃/ex(!read) slot₄/ctx(!read)] 1 slot₂/__context__ 2 (= slot₄/ctx %₁) 3 (return %₁) -9 TestMod.@foo -10 (return %₉) +10 (latestworld) +11 TestMod.@foo +12 (return %₁₁) ######################################## # Scope for symbols emitted by macros is the module where the method was diff --git a/test/misc_ir.jl b/test/misc_ir.jl index d073cf97..a2b9632c 100644 --- a/test/misc_ir.jl +++ b/test/misc_ir.jl @@ -390,3 +390,12 @@ LoweringError: x... └──┘ ── `...` expression outside call +######################################## +# `include` should increment world age +include("hi.jl") +#--------------------- +1 TestMod.include +2 (call %₁ "hi.jl") +3 (latestworld) +4 (return %₂) + diff --git a/test/scopes_ir.jl b/test/scopes_ir.jl index 4434f6f7..9fd6b826 100644 --- a/test/scopes_ir.jl +++ b/test/scopes_ir.jl @@ -73,19 +73,22 @@ end 1 (call core.svec) 2 (call core.svec) 3 (call JuliaLowering.eval_closure_type TestMod :#f##0 %₁ %₂) -4 TestMod.#f##0 -5 (new %₄) -6 (= slot₁/f %₅) -7 TestMod.#f##0 -8 (call core.svec %₇) -9 (call core.svec) -10 SourceLocation::1:5 -11 (call core.svec %₈ %₉ %₁₀) -12 --- method core.nothing %₁₁ +4 (latestworld) +5 TestMod.#f##0 +6 (new %₅) +7 (= slot₁/f %₆) +8 (latestworld) +9 TestMod.#f##0 +10 (call core.svec %₉) +11 (call core.svec) +12 SourceLocation::1:5 +13 (call core.svec %₁₀ %₁₁ %₁₂) +14 --- method core.nothing %₁₃ slots: [slot₁/#self#(!read)] 1 TestMod.body 2 (return %₁) -13 (return core.nothing) +15 (latestworld) +16 (return core.nothing) ######################################## # Error: Invalid `let` var with K"::" @@ -142,18 +145,20 @@ end 3 slot₁/y 4 (call core.setfield! %₃ :contents %₂) 5 (method TestMod.f) -6 TestMod.f -7 (call core.Typeof %₆) -8 (call core.svec %₇ core.Any) -9 (call core.svec) -10 SourceLocation::3:14 -11 (call core.svec %₈ %₉ %₁₀) -12 --- method core.nothing %₁₁ +6 (latestworld) +7 TestMod.f +8 (call core.Typeof %₇) +9 (call core.svec %₈ core.Any) +10 (call core.svec) +11 SourceLocation::3:14 +12 (call core.svec %₉ %₁₀ %₁₁) +13 --- method core.nothing %₁₂ slots: [slot₁/#self#(!read) slot₂/x(!read)] 1 (call core.tuple false true true) 2 (return %₁) -13 TestMod.f -14 (return %₁₃) +14 (latestworld) +15 TestMod.f +16 (return %₁₅) ######################################## # @islocal with global @@ -163,7 +168,8 @@ begin end #--------------------- 1 (global TestMod.x) -2 (return false) +2 (latestworld) +3 (return false) ######################################## # @locals with local and global @@ -175,13 +181,14 @@ end #--------------------- 1 (newvar slot₁/y) 2 (global TestMod.x) -3 (call core.apply_type top.Dict core.Symbol core.Any) -4 (call %₃) -5 (isdefined slot₁/y) -6 (gotoifnot %₅ label₉) -7 slot₁/y -8 (call top.setindex! %₄ %₇ :y) -9 (return %₄) +3 (latestworld) +4 (call core.apply_type top.Dict core.Symbol core.Any) +5 (call %₄) +6 (isdefined slot₁/y) +7 (gotoifnot %₆ label₁₀) +8 slot₁/y +9 (call top.setindex! %₅ %₈ :y) +10 (return %₅) ######################################## # @locals with function args (TODO: static parameters) @@ -190,21 +197,23 @@ function f(z) end #--------------------- 1 (method TestMod.f) -2 TestMod.f -3 (call core.Typeof %₂) -4 (call core.svec %₃ core.Any) -5 (call core.svec) -6 SourceLocation::1:10 -7 (call core.svec %₄ %₅ %₆) -8 --- method core.nothing %₇ +2 (latestworld) +3 TestMod.f +4 (call core.Typeof %₃) +5 (call core.svec %₄ core.Any) +6 (call core.svec) +7 SourceLocation::1:10 +8 (call core.svec %₅ %₆ %₇) +9 --- method core.nothing %₈ slots: [slot₁/#self#(!read) slot₂/z] 1 (call core.apply_type top.Dict core.Symbol core.Any) 2 (call %₁) 3 (gotoifnot true label₅) 4 (call top.setindex! %₂ slot₂/z :z) 5 (return %₂) -9 TestMod.f -10 (return %₉) +10 (latestworld) +11 TestMod.f +12 (return %₁₁) ######################################## # Error: Duplicate function argument names diff --git a/test/typedefs_ir.jl b/test/typedefs_ir.jl index 14f0b1cc..b0b2312c 100644 --- a/test/typedefs_ir.jl +++ b/test/typedefs_ir.jl @@ -191,17 +191,19 @@ abstract type A end 2 (call core._abstracttype TestMod :A %₁) 3 (= slot₁/A %₂) 4 (call core._setsuper! %₂ core.Any) -5 (call core._typebody! %₂) -6 (global TestMod.A) -7 (const TestMod.A) -8 (isdefined TestMod.A) -9 (gotoifnot %₈ label₁₄) -10 TestMod.A -11 (call core._equiv_typedef %₁₀ %₂) -12 (gotoifnot %₁₁ label₁₄) -13 (goto label₁₅) -14 (= TestMod.A %₂) -15 (return core.nothing) +5 slot₁/A +6 (call core._typebody! false %₅) +7 (global TestMod.A) +8 (latestworld) +9 (call core.isdefinedglobal TestMod :A false) +10 (gotoifnot %₉ label₁₅) +11 TestMod.A +12 (call core._equiv_typedef %₁₁ %₂) +13 (gotoifnot %₁₂ label₁₅) +14 (goto label₁₆) +15 (constdecl TestMod.A %₂) +16 (latestworld) +17 (return core.nothing) ######################################## # Abstract type definition with supertype @@ -212,17 +214,19 @@ abstract type A <: B end 3 (= slot₁/A %₂) 4 TestMod.B 5 (call core._setsuper! %₂ %₄) -6 (call core._typebody! %₂) -7 (global TestMod.A) -8 (const TestMod.A) -9 (isdefined TestMod.A) -10 (gotoifnot %₉ label₁₅) -11 TestMod.A -12 (call core._equiv_typedef %₁₁ %₂) -13 (gotoifnot %₁₂ label₁₅) -14 (goto label₁₆) -15 (= TestMod.A %₂) -16 (return core.nothing) +6 slot₁/A +7 (call core._typebody! false %₆) +8 (global TestMod.A) +9 (latestworld) +10 (call core.isdefinedglobal TestMod :A false) +11 (gotoifnot %₁₀ label₁₆) +12 TestMod.A +13 (call core._equiv_typedef %₁₂ %₂) +14 (gotoifnot %₁₃ label₁₆) +15 (goto label₁₇) +16 (constdecl TestMod.A %₂) +17 (latestworld) +18 (return core.nothing) ######################################## # Abstract type definition with multiple typevars @@ -237,17 +241,19 @@ abstract type A{X, Y <: X} end 7 (call core._abstracttype TestMod :A %₆) 8 (= slot₁/A %₇) 9 (call core._setsuper! %₇ core.Any) -10 (call core._typebody! %₇) -11 (global TestMod.A) -12 (const TestMod.A) -13 (isdefined TestMod.A) -14 (gotoifnot %₁₃ label₁₉) -15 TestMod.A -16 (call core._equiv_typedef %₁₅ %₇) -17 (gotoifnot %₁₆ label₁₉) -18 (goto label₂₀) -19 (= TestMod.A %₇) -20 (return core.nothing) +10 slot₁/A +11 (call core._typebody! false %₁₀) +12 (global TestMod.A) +13 (latestworld) +14 (call core.isdefinedglobal TestMod :A false) +15 (gotoifnot %₁₄ label₂₀) +16 TestMod.A +17 (call core._equiv_typedef %₁₆ %₇) +18 (gotoifnot %₁₇ label₂₀) +19 (goto label₂₁) +20 (constdecl TestMod.A %₇) +21 (latestworld) +22 (return core.nothing) ######################################## # Error: Abstract type definition with bad signature @@ -293,17 +299,19 @@ primitive type P 8 end 2 (call core._primitivetype TestMod :P %₁ 8) 3 (= slot₁/P %₂) 4 (call core._setsuper! %₂ core.Any) -5 (call core._typebody! %₂) -6 (global TestMod.P) -7 (const TestMod.P) -8 (isdefined TestMod.P) -9 (gotoifnot %₈ label₁₄) -10 TestMod.P -11 (call core._equiv_typedef %₁₀ %₂) -12 (gotoifnot %₁₁ label₁₄) -13 (goto label₁₅) -14 (= TestMod.P %₂) -15 (return core.nothing) +5 slot₁/P +6 (call core._typebody! false %₅) +7 (global TestMod.P) +8 (latestworld) +9 (call core.isdefinedglobal TestMod :P false) +10 (gotoifnot %₉ label₁₅) +11 TestMod.P +12 (call core._equiv_typedef %₁₁ %₂) +13 (gotoifnot %₁₂ label₁₅) +14 (goto label₁₆) +15 (constdecl TestMod.P %₂) +16 (latestworld) +17 (return core.nothing) ######################################## # Complex primitive type definition @@ -318,17 +326,19 @@ primitive type P{X,Y} <: Z 32 end 7 (= slot₁/P %₆) 8 TestMod.Z 9 (call core._setsuper! %₆ %₈) -10 (call core._typebody! %₆) -11 (global TestMod.P) -12 (const TestMod.P) -13 (isdefined TestMod.P) -14 (gotoifnot %₁₃ label₁₉) -15 TestMod.P -16 (call core._equiv_typedef %₁₅ %₆) -17 (gotoifnot %₁₆ label₁₉) -18 (goto label₂₀) -19 (= TestMod.P %₆) -20 (return core.nothing) +10 slot₁/P +11 (call core._typebody! false %₁₀) +12 (global TestMod.P) +13 (latestworld) +14 (call core.isdefinedglobal TestMod :P false) +15 (gotoifnot %₁₄ label₂₀) +16 TestMod.P +17 (call core._equiv_typedef %₁₆ %₆) +18 (gotoifnot %₁₇ label₂₀) +19 (goto label₂₁) +20 (constdecl TestMod.P %₆) +21 (latestworld) +22 (return core.nothing) ######################################## # Primitive type definition with computed size (should this be allowed??) @@ -340,17 +350,19 @@ primitive type P P_nbits() end 4 (call core._primitivetype TestMod :P %₁ %₃) 5 (= slot₁/P %₄) 6 (call core._setsuper! %₄ core.Any) -7 (call core._typebody! %₄) -8 (global TestMod.P) -9 (const TestMod.P) -10 (isdefined TestMod.P) -11 (gotoifnot %₁₀ label₁₆) -12 TestMod.P -13 (call core._equiv_typedef %₁₂ %₄) -14 (gotoifnot %₁₃ label₁₆) -15 (goto label₁₇) -16 (= TestMod.P %₄) -17 (return core.nothing) +7 slot₁/P +8 (call core._typebody! false %₇) +9 (global TestMod.P) +10 (latestworld) +11 (call core.isdefinedglobal TestMod :P false) +12 (gotoifnot %₁₁ label₁₇) +13 TestMod.P +14 (call core._equiv_typedef %₁₃ %₄) +15 (gotoifnot %₁₄ label₁₇) +16 (goto label₁₈) +17 (constdecl TestMod.P %₄) +18 (latestworld) +19 (return core.nothing) ######################################## # Empty struct @@ -358,41 +370,45 @@ struct X end #--------------------- 1 (global TestMod.X) -2 (const TestMod.X) +2 (latestworld) 3 (call core.svec) 4 (call core.svec) 5 (call core.svec) 6 (call core._structtype TestMod :X %₃ %₄ %₅ false 0) 7 (= slot₁/X %₆) 8 (call core._setsuper! %₆ core.Any) -9 (isdefined TestMod.X) -10 (gotoifnot %₉ label₂₀) +9 (call core.isdefinedglobal TestMod :X false) +10 (gotoifnot %₉ label₁₄) 11 TestMod.X -12 (call core._equiv_typedef %₁₁ %₆) -13 (gotoifnot %₁₂ label₁₇) -14 TestMod.X -15 (= slot₁/X %₁₄) -16 (goto label₁₉) -17 slot₁/X -18 (= TestMod.X %₁₇) -19 (goto label₂₂) -20 slot₁/X -21 (= TestMod.X %₂₀) -22 slot₁/X +12 (= slot₂/if_val (call core._equiv_typedef %₁₁ %₆)) +13 (goto label₁₅) +14 (= slot₂/if_val false) +15 slot₂/if_val +16 (gotoifnot %₁₅ label₂₀) +17 TestMod.X +18 (= slot₃/if_val %₁₇) +19 (goto label₂₁) +20 (= slot₃/if_val false) +21 slot₃/if_val +22 (gotoifnot %₁₅ label₂₃) 23 (call core.svec) -24 (call core._typebody! %₂₂ %₂₃) -25 TestMod.X -26 (call core.apply_type core.Type %₂₅) -27 (call core.svec %₂₆) -28 (call core.svec) -29 SourceLocation::1:1 -30 (call core.svec %₂₇ %₂₈ %₂₉) -31 --- method core.nothing %₃₀ +24 (call core._typebody! %₂₁ %₆ %₂₃) +25 (constdecl TestMod.X %₂₄) +26 (latestworld) +27 (latestworld) +28 TestMod.X +29 (call core.apply_type core.Type %₂₈) +30 (call core.svec %₂₉) +31 (call core.svec) +32 SourceLocation::1:1 +33 (call core.svec %₃₀ %₃₁ %₃₂) +34 --- method core.nothing %₃₃ slots: [slot₁/#self#(!read)] 1 TestMod.X 2 (new %₁) 3 (return %₂) -32 (return core.nothing) +35 (latestworld) +36 (return core.nothing) ######################################## # Basic struct @@ -403,41 +419,44 @@ struct X end #--------------------- 1 (global TestMod.X) -2 (const TestMod.X) +2 (latestworld) 3 (call core.svec) 4 (call core.svec :a :b :c) 5 (call core.svec) 6 (call core._structtype TestMod :X %₃ %₄ %₅ false 3) 7 (= slot₁/X %₆) 8 (call core._setsuper! %₆ core.Any) -9 (isdefined TestMod.X) -10 (gotoifnot %₉ label₂₀) +9 (call core.isdefinedglobal TestMod :X false) +10 (gotoifnot %₉ label₁₄) 11 TestMod.X -12 (call core._equiv_typedef %₁₁ %₆) -13 (gotoifnot %₁₂ label₁₇) -14 TestMod.X -15 (= slot₁/X %₁₄) -16 (goto label₁₉) -17 slot₁/X -18 (= TestMod.X %₁₇) -19 (goto label₂₂) -20 slot₁/X -21 (= TestMod.X %₂₀) -22 slot₁/X +12 (= slot₂/if_val (call core._equiv_typedef %₁₁ %₆)) +13 (goto label₁₅) +14 (= slot₂/if_val false) +15 slot₂/if_val +16 (gotoifnot %₁₅ label₂₀) +17 TestMod.X +18 (= slot₃/if_val %₁₇) +19 (goto label₂₁) +20 (= slot₃/if_val false) +21 slot₃/if_val +22 (gotoifnot %₁₅ label₂₃) 23 TestMod.T 24 (call core.svec core.Any %₂₃ core.Any) -25 (call core._typebody! %₂₂ %₂₄) -26 TestMod.T -27 (call core.=== core.Any %₂₆) -28 (gotoifnot %₂₇ label₃₀) -29 (goto label₃₇) -30 TestMod.X -31 (call core.apply_type core.Type %₃₀) -32 (call core.svec %₃₁ core.Any core.Any core.Any) -33 (call core.svec) -34 SourceLocation::1:1 -35 (call core.svec %₃₂ %₃₃ %₃₄) -36 --- method core.nothing %₃₅ +25 (call core._typebody! %₂₁ %₆ %₂₄) +26 (constdecl TestMod.X %₂₅) +27 (latestworld) +28 TestMod.T +29 (call core.=== core.Any %₂₈) +30 (gotoifnot %₂₉ label₃₂) +31 (goto label₄₁) +32 (latestworld) +33 TestMod.X +34 (call core.apply_type core.Type %₃₃) +35 (call core.svec %₃₄ core.Any core.Any core.Any) +36 (call core.svec) +37 SourceLocation::1:1 +38 (call core.svec %₃₅ %₃₆ %₃₇) +39 --- method core.nothing %₃₈ slots: [slot₁/#ctor-self# slot₂/a slot₃/b slot₄/c slot₅/tmp] 1 (call core.fieldtype slot₁/#ctor-self# 2) 2 slot₃/b @@ -451,19 +470,22 @@ end 10 slot₅/tmp 11 (new slot₁/#ctor-self# slot₂/a %₁₀ slot₄/c) 12 (return %₁₁) -37 TestMod.X -38 (call core.apply_type core.Type %₃₇) -39 TestMod.T -40 (call core.svec %₃₈ core.Any %₃₉ core.Any) -41 (call core.svec) -42 SourceLocation::1:1 -43 (call core.svec %₄₀ %₄₁ %₄₂) -44 --- method core.nothing %₄₃ +40 (latestworld) +41 (latestworld) +42 TestMod.X +43 (call core.apply_type core.Type %₄₂) +44 TestMod.T +45 (call core.svec %₄₃ core.Any %₄₄ core.Any) +46 (call core.svec) +47 SourceLocation::1:1 +48 (call core.svec %₄₅ %₄₆ %₄₇) +49 --- method core.nothing %₄₈ slots: [slot₁/#self#(!read) slot₂/a slot₃/b slot₄/c] 1 TestMod.X 2 (new %₁ slot₂/a slot₃/b slot₄/c) 3 (return %₂) -45 (return core.nothing) +50 (latestworld) +51 (return core.nothing) ######################################## # Struct with supertype and type params @@ -471,7 +493,7 @@ struct X{U, S <: V <: T} <: Z end #--------------------- 1 (global TestMod.X) -2 (const TestMod.X) +2 (latestworld) 3 (= slot₂/U (call core.TypeVar :U)) 4 TestMod.S 5 TestMod.T @@ -485,50 +507,54 @@ end 13 (= slot₄/X %₁₂) 14 TestMod.Z 15 (call core._setsuper! %₁₂ %₁₄) -16 (isdefined TestMod.X) -17 (gotoifnot %₁₆ label₃₇) +16 (call core.isdefinedglobal TestMod :X false) +17 (gotoifnot %₁₆ label₂₁) 18 TestMod.X -19 (call core._equiv_typedef %₁₈ %₁₂) -20 (gotoifnot %₁₉ label₃₄) -21 TestMod.X -22 (= slot₄/X %₂₁) -23 TestMod.X -24 (call top.getproperty %₂₃ :body) -25 (call top.getproperty %₂₄ :body) -26 (call top.getproperty %₂₅ :parameters) -27 (call top.indexed_iterate %₂₆ 1) -28 (= slot₂/U (call core.getfield %₂₇ 1)) -29 (= slot₁/iterstate (call core.getfield %₂₇ 2)) -30 slot₁/iterstate -31 (call top.indexed_iterate %₂₆ 2 %₃₀) -32 (= slot₃/V (call core.getfield %₃₁ 1)) -33 (goto label₃₆) -34 slot₄/X -35 (= TestMod.X %₃₄) -36 (goto label₃₉) -37 slot₄/X -38 (= TestMod.X %₃₇) -39 slot₄/X +19 (= slot₅/if_val (call core._equiv_typedef %₁₈ %₁₂)) +20 (goto label₂₂) +21 (= slot₅/if_val false) +22 slot₅/if_val +23 (gotoifnot %₂₂ label₂₇) +24 TestMod.X +25 (= slot₆/if_val %₂₄) +26 (goto label₂₈) +27 (= slot₆/if_val false) +28 slot₆/if_val +29 (gotoifnot %₂₂ label₄₀) +30 TestMod.X +31 (call top.getproperty %₃₀ :body) +32 (call top.getproperty %₃₁ :body) +33 (call top.getproperty %₃₂ :parameters) +34 (call top.indexed_iterate %₃₃ 1) +35 (= slot₂/U (call core.getfield %₃₄ 1)) +36 (= slot₁/iterstate (call core.getfield %₃₄ 2)) +37 slot₁/iterstate +38 (call top.indexed_iterate %₃₃ 2 %₃₇) +39 (= slot₃/V (call core.getfield %₃₈ 1)) 40 (call core.svec) -41 (call core._typebody! %₃₉ %₄₀) -42 slot₂/U -43 slot₃/V -44 TestMod.X +41 (call core._typebody! %₂₈ %₁₂ %₄₀) +42 (constdecl TestMod.X %₄₁) +43 (latestworld) +44 (latestworld) 45 slot₂/U 46 slot₃/V -47 (call core.apply_type %₄₄ %₄₅ %₄₆) -48 (call core.apply_type core.Type %₄₇) -49 (call core.UnionAll %₄₃ %₄₈) -50 (call core.UnionAll %₄₂ %₄₉) -51 (call core.svec %₅₀) -52 (call core.svec) -53 SourceLocation::1:1 -54 (call core.svec %₅₁ %₅₂ %₅₃) -55 --- method core.nothing %₅₄ +47 TestMod.X +48 slot₂/U +49 slot₃/V +50 (call core.apply_type %₄₇ %₄₈ %₄₉) +51 (call core.apply_type core.Type %₅₀) +52 (call core.UnionAll %₄₆ %₅₁) +53 (call core.UnionAll %₄₅ %₅₂) +54 (call core.svec %₅₃) +55 (call core.svec) +56 SourceLocation::1:1 +57 (call core.svec %₅₄ %₅₅ %₅₆) +58 --- method core.nothing %₅₇ slots: [slot₁/#ctor-self#] 1 (new slot₁/#ctor-self#) 2 (return %₁) -56 (return core.nothing) +59 (latestworld) +60 (return core.nothing) ######################################## # Struct with const and atomic fields @@ -539,41 +565,45 @@ struct X end #--------------------- 1 (global TestMod.X) -2 (const TestMod.X) +2 (latestworld) 3 (call core.svec) 4 (call core.svec :a :b :c) 5 (call core.svec 1 :const 2 :atomic 3 :atomic 3 :const) 6 (call core._structtype TestMod :X %₃ %₄ %₅ false 3) 7 (= slot₁/X %₆) 8 (call core._setsuper! %₆ core.Any) -9 (isdefined TestMod.X) -10 (gotoifnot %₉ label₂₀) +9 (call core.isdefinedglobal TestMod :X false) +10 (gotoifnot %₉ label₁₄) 11 TestMod.X -12 (call core._equiv_typedef %₁₁ %₆) -13 (gotoifnot %₁₂ label₁₇) -14 TestMod.X -15 (= slot₁/X %₁₄) -16 (goto label₁₉) -17 slot₁/X -18 (= TestMod.X %₁₇) -19 (goto label₂₂) -20 slot₁/X -21 (= TestMod.X %₂₀) -22 slot₁/X +12 (= slot₂/if_val (call core._equiv_typedef %₁₁ %₆)) +13 (goto label₁₅) +14 (= slot₂/if_val false) +15 slot₂/if_val +16 (gotoifnot %₁₅ label₂₀) +17 TestMod.X +18 (= slot₃/if_val %₁₇) +19 (goto label₂₁) +20 (= slot₃/if_val false) +21 slot₃/if_val +22 (gotoifnot %₁₅ label₂₃) 23 (call core.svec core.Any core.Any core.Any) -24 (call core._typebody! %₂₂ %₂₃) -25 TestMod.X -26 (call core.apply_type core.Type %₂₅) -27 (call core.svec %₂₆ core.Any core.Any core.Any) -28 (call core.svec) -29 SourceLocation::1:1 -30 (call core.svec %₂₇ %₂₈ %₂₉) -31 --- method core.nothing %₃₀ +24 (call core._typebody! %₂₁ %₆ %₂₃) +25 (constdecl TestMod.X %₂₄) +26 (latestworld) +27 (latestworld) +28 TestMod.X +29 (call core.apply_type core.Type %₂₈) +30 (call core.svec %₂₉ core.Any core.Any core.Any) +31 (call core.svec) +32 SourceLocation::1:1 +33 (call core.svec %₃₀ %₃₁ %₃₂) +34 --- method core.nothing %₃₃ slots: [slot₁/#self#(!read) slot₂/a slot₃/b slot₄/c] 1 TestMod.X 2 (new %₁ slot₂/a slot₃/b slot₄/c) 3 (return %₂) -32 (return core.nothing) +35 (latestworld) +36 (return core.nothing) ######################################## # Documented struct @@ -588,50 +618,54 @@ struct X end #--------------------- 1 (global TestMod.X) -2 (const TestMod.X) +2 (latestworld) 3 (call core.svec) 4 (call core.svec :a :b) 5 (call core.svec) 6 (call core._structtype TestMod :X %₃ %₄ %₅ false 2) 7 (= slot₁/X %₆) 8 (call core._setsuper! %₆ core.Any) -9 (isdefined TestMod.X) -10 (gotoifnot %₉ label₂₀) +9 (call core.isdefinedglobal TestMod :X false) +10 (gotoifnot %₉ label₁₄) 11 TestMod.X -12 (call core._equiv_typedef %₁₁ %₆) -13 (gotoifnot %₁₂ label₁₇) -14 TestMod.X -15 (= slot₁/X %₁₄) -16 (goto label₁₉) -17 slot₁/X -18 (= TestMod.X %₁₇) -19 (goto label₂₂) -20 slot₁/X -21 (= TestMod.X %₂₀) -22 slot₁/X +12 (= slot₂/if_val (call core._equiv_typedef %₁₁ %₆)) +13 (goto label₁₅) +14 (= slot₂/if_val false) +15 slot₂/if_val +16 (gotoifnot %₁₅ label₂₀) +17 TestMod.X +18 (= slot₃/if_val %₁₇) +19 (goto label₂₁) +20 (= slot₃/if_val false) +21 slot₃/if_val +22 (gotoifnot %₁₅ label₂₃) 23 (call core.svec core.Any core.Any) -24 (call core._typebody! %₂₂ %₂₃) -25 TestMod.X -26 (call core.apply_type core.Type %₂₅) -27 (call core.svec %₂₆ core.Any core.Any) -28 (call core.svec) -29 SourceLocation::4:1 -30 (call core.svec %₂₇ %₂₈ %₂₉) -31 --- method core.nothing %₃₀ +24 (call core._typebody! %₂₁ %₆ %₂₃) +25 (constdecl TestMod.X %₂₄) +26 (latestworld) +27 (latestworld) +28 TestMod.X +29 (call core.apply_type core.Type %₂₈) +30 (call core.svec %₂₉ core.Any core.Any) +31 (call core.svec) +32 SourceLocation::4:1 +33 (call core.svec %₃₀ %₃₁ %₃₂) +34 --- method core.nothing %₃₃ slots: [slot₁/#self#(!read) slot₂/a slot₃/b] 1 TestMod.X 2 (new %₁ slot₂/a slot₃/b) 3 (return %₂) -32 JuliaLowering.bind_docs! -33 (call core.tuple :field_docs) -34 (call core.apply_type core.NamedTuple %₃₃) -35 (call core.svec 1 "field a docs" 2 "field b docs") -36 (call core.tuple %₃₅) -37 (call %₃₄ %₃₆) -38 TestMod.X -39 SourceLocation::4:1 -40 (call core.kwcall %₃₇ %₃₂ %₃₈ "X docs\n" %₃₉) -41 (return core.nothing) +35 (latestworld) +36 JuliaLowering.bind_docs! +37 (call core.tuple :field_docs) +38 (call core.apply_type core.NamedTuple %₃₇) +39 (call core.svec 1 "field a docs" 2 "field b docs") +40 (call core.tuple %₃₉) +41 (call %₃₈ %₄₀) +42 TestMod.X +43 SourceLocation::4:1 +44 (call core.kwcall %₄₁ %₃₆ %₄₂ "X docs\n" %₄₃) +45 (return core.nothing) ######################################## # Struct with outer constructor @@ -640,7 +674,7 @@ struct X{U} end #--------------------- 1 (global TestMod.X) -2 (const TestMod.X) +2 (latestworld) 3 (= slot₁/U (call core.TypeVar :U)) 4 slot₁/U 5 (call core.svec %₄) @@ -649,39 +683,42 @@ end 8 (call core._structtype TestMod :X %₅ %₆ %₇ false 1) 9 (= slot₂/X %₈) 10 (call core._setsuper! %₈ core.Any) -11 (isdefined TestMod.X) -12 (gotoifnot %₁₁ label₂₇) +11 (call core.isdefinedglobal TestMod :X false) +12 (gotoifnot %₁₁ label₁₆) 13 TestMod.X -14 (call core._equiv_typedef %₁₃ %₈) -15 (gotoifnot %₁₄ label₂₄) -16 TestMod.X -17 (= slot₂/X %₁₆) -18 TestMod.X -19 (call top.getproperty %₁₈ :body) -20 (call top.getproperty %₁₉ :parameters) -21 (call top.indexed_iterate %₂₀ 1) -22 (= slot₁/U (call core.getfield %₂₁ 1)) -23 (goto label₂₆) -24 slot₂/X -25 (= TestMod.X %₂₄) -26 (goto label₂₉) -27 slot₂/X -28 (= TestMod.X %₂₇) -29 slot₂/X +14 (= slot₃/if_val (call core._equiv_typedef %₁₃ %₈)) +15 (goto label₁₇) +16 (= slot₃/if_val false) +17 slot₃/if_val +18 (gotoifnot %₁₇ label₂₂) +19 TestMod.X +20 (= slot₄/if_val %₁₉) +21 (goto label₂₃) +22 (= slot₄/if_val false) +23 slot₄/if_val +24 (gotoifnot %₁₇ label₃₀) +25 TestMod.X +26 (call top.getproperty %₂₅ :body) +27 (call top.getproperty %₂₆ :parameters) +28 (call top.indexed_iterate %₂₇ 1) +29 (= slot₁/U (call core.getfield %₂₈ 1)) 30 slot₁/U 31 (call core.svec %₃₀) -32 (call core._typebody! %₂₉ %₃₁) -33 slot₁/U -34 TestMod.X -35 slot₁/U -36 (call core.apply_type %₃₄ %₃₅) -37 (call core.apply_type core.Type %₃₆) -38 (call core.UnionAll %₃₃ %₃₇) -39 (call core.svec %₃₈ core.Any) -40 (call core.svec) -41 SourceLocation::1:1 -42 (call core.svec %₃₉ %₄₀ %₄₁) -43 --- method core.nothing %₄₂ +32 (call core._typebody! %₂₃ %₈ %₃₁) +33 (constdecl TestMod.X %₃₂) +34 (latestworld) +35 (latestworld) +36 slot₁/U +37 TestMod.X +38 slot₁/U +39 (call core.apply_type %₃₇ %₃₈) +40 (call core.apply_type core.Type %₃₉) +41 (call core.UnionAll %₃₆ %₄₀) +42 (call core.svec %₄₁ core.Any) +43 (call core.svec) +44 SourceLocation::1:1 +45 (call core.svec %₄₂ %₄₃ %₄₄) +46 --- method core.nothing %₄₅ slots: [slot₁/#ctor-self# slot₂/x slot₃/tmp] 1 (call core.fieldtype slot₁/#ctor-self# 1) 2 slot₂/x @@ -695,22 +732,24 @@ end 10 slot₃/tmp 11 (new slot₁/#ctor-self# %₁₀) 12 (return %₁₁) -44 TestMod.X -45 (call core.apply_type core.Type %₄₄) -46 slot₁/U -47 (call core.svec %₄₅ %₄₆) -48 slot₁/U -49 (call core.svec %₄₈) -50 SourceLocation::1:1 -51 (call core.svec %₄₇ %₄₉ %₅₀) -52 --- method core.nothing %₅₁ +47 (latestworld) +48 (latestworld) +49 TestMod.X +50 (call core.apply_type core.Type %₄₉) +51 slot₁/U +52 (call core.svec %₅₀ %₅₁) +53 slot₁/U +54 (call core.svec %₅₃) +55 SourceLocation::1:1 +56 (call core.svec %₅₂ %₅₄ %₅₅) +57 --- method core.nothing %₅₆ slots: [slot₁/#self#(!read) slot₂/x] 1 TestMod.X - 2 static_parameter₁ - 3 (call core.apply_type %₁ %₂) - 4 (new %₃ slot₂/x) - 5 (return %₄) -53 (return core.nothing) + 2 (call core.apply_type %₁ static_parameter₁) + 3 (new %₂ slot₂/x) + 4 (return %₃) +58 (latestworld) +59 (return core.nothing) ######################################## # Struct with outer constructor where one typevar is constrained by the other @@ -720,7 +759,7 @@ struct X{T, S <: Vector{T}} end #--------------------- 1 (global TestMod.X) -2 (const TestMod.X) +2 (latestworld) 3 (= slot₃/T (call core.TypeVar :T)) 4 TestMod.Vector 5 slot₃/T @@ -734,49 +773,52 @@ end 13 (call core._structtype TestMod :X %₁₀ %₁₁ %₁₂ false 1) 14 (= slot₄/X %₁₃) 15 (call core._setsuper! %₁₃ core.Any) -16 (isdefined TestMod.X) -17 (gotoifnot %₁₆ label₃₇) +16 (call core.isdefinedglobal TestMod :X false) +17 (gotoifnot %₁₆ label₂₁) 18 TestMod.X -19 (call core._equiv_typedef %₁₈ %₁₃) -20 (gotoifnot %₁₉ label₃₄) -21 TestMod.X -22 (= slot₄/X %₂₁) -23 TestMod.X -24 (call top.getproperty %₂₃ :body) -25 (call top.getproperty %₂₄ :body) -26 (call top.getproperty %₂₅ :parameters) -27 (call top.indexed_iterate %₂₆ 1) -28 (= slot₃/T (call core.getfield %₂₇ 1)) -29 (= slot₁/iterstate (call core.getfield %₂₇ 2)) -30 slot₁/iterstate -31 (call top.indexed_iterate %₂₆ 2 %₃₀) -32 (= slot₂/S (call core.getfield %₃₁ 1)) -33 (goto label₃₆) -34 slot₄/X -35 (= TestMod.X %₃₄) -36 (goto label₃₉) -37 slot₄/X -38 (= TestMod.X %₃₇) -39 slot₄/X +19 (= slot₅/if_val (call core._equiv_typedef %₁₈ %₁₃)) +20 (goto label₂₂) +21 (= slot₅/if_val false) +22 slot₅/if_val +23 (gotoifnot %₂₂ label₂₇) +24 TestMod.X +25 (= slot₆/if_val %₂₄) +26 (goto label₂₈) +27 (= slot₆/if_val false) +28 slot₆/if_val +29 (gotoifnot %₂₂ label₄₀) +30 TestMod.X +31 (call top.getproperty %₃₀ :body) +32 (call top.getproperty %₃₁ :body) +33 (call top.getproperty %₃₂ :parameters) +34 (call top.indexed_iterate %₃₃ 1) +35 (= slot₃/T (call core.getfield %₃₄ 1)) +36 (= slot₁/iterstate (call core.getfield %₃₄ 2)) +37 slot₁/iterstate +38 (call top.indexed_iterate %₃₃ 2 %₃₇) +39 (= slot₂/S (call core.getfield %₃₈ 1)) 40 TestMod.Vector 41 slot₂/S 42 (call core.apply_type %₄₀ %₄₁) 43 (call core.svec %₄₂) -44 (call core._typebody! %₃₉ %₄₃) -45 slot₃/T -46 slot₂/S -47 TestMod.X +44 (call core._typebody! %₂₈ %₁₃ %₄₃) +45 (constdecl TestMod.X %₄₄) +46 (latestworld) +47 (latestworld) 48 slot₃/T 49 slot₂/S -50 (call core.apply_type %₄₇ %₄₈ %₄₉) -51 (call core.apply_type core.Type %₅₀) -52 (call core.UnionAll %₄₆ %₅₁) -53 (call core.UnionAll %₄₅ %₅₂) -54 (call core.svec %₅₃ core.Any) -55 (call core.svec) -56 SourceLocation::1:1 -57 (call core.svec %₅₄ %₅₅ %₅₆) -58 --- method core.nothing %₅₇ +50 TestMod.X +51 slot₃/T +52 slot₂/S +53 (call core.apply_type %₅₀ %₅₁ %₅₂) +54 (call core.apply_type core.Type %₅₃) +55 (call core.UnionAll %₄₉ %₅₄) +56 (call core.UnionAll %₄₈ %₅₅) +57 (call core.svec %₅₆ core.Any) +58 (call core.svec) +59 SourceLocation::1:1 +60 (call core.svec %₅₇ %₅₈ %₅₉) +61 --- method core.nothing %₆₀ slots: [slot₁/#ctor-self# slot₂/v slot₃/tmp] 1 (call core.fieldtype slot₁/#ctor-self# 1) 2 slot₂/v @@ -790,26 +832,27 @@ end 10 slot₃/tmp 11 (new slot₁/#ctor-self# %₁₀) 12 (return %₁₁) -59 TestMod.X -60 (call core.apply_type core.Type %₅₉) -61 TestMod.Vector -62 slot₂/S -63 (call core.apply_type %₆₁ %₆₂) -64 (call core.svec %₆₀ %₆₃) -65 slot₃/T -66 slot₂/S -67 (call core.svec %₆₅ %₆₆) -68 SourceLocation::1:1 -69 (call core.svec %₆₄ %₆₇ %₆₈) -70 --- method core.nothing %₆₉ +62 (latestworld) +63 (latestworld) +64 TestMod.X +65 (call core.apply_type core.Type %₆₄) +66 TestMod.Vector +67 slot₂/S +68 (call core.apply_type %₆₆ %₆₇) +69 (call core.svec %₆₅ %₆₈) +70 slot₃/T +71 slot₂/S +72 (call core.svec %₇₀ %₇₁) +73 SourceLocation::1:1 +74 (call core.svec %₆₉ %₇₂ %₇₃) +75 --- method core.nothing %₇₄ slots: [slot₁/#self#(!read) slot₂/v] 1 TestMod.X - 2 static_parameter₁ - 3 static_parameter₂ - 4 (call core.apply_type %₁ %₂ %₃) - 5 (new %₄ slot₂/v) - 6 (return %₅) -71 (return core.nothing) + 2 (call core.apply_type %₁ static_parameter₁ static_parameter₂) + 3 (new %₂ slot₂/v) + 4 (return %₃) +76 (latestworld) +77 (return core.nothing) ######################################## # User defined inner constructors and helper functions for structs without type params @@ -827,53 +870,59 @@ end #--------------------- 1 (= slot₂/f (call core.Box)) 2 (global TestMod.X) -3 (const TestMod.X) +3 (latestworld) 4 (call core.svec) 5 (call core.svec :x) 6 (call core.svec) 7 (call core._structtype TestMod :X %₄ %₅ %₆ false 1) 8 (= slot₁/X %₇) 9 (call core._setsuper! %₇ core.Any) -10 (isdefined TestMod.X) -11 (gotoifnot %₁₀ label₂₁) +10 (call core.isdefinedglobal TestMod :X false) +11 (gotoifnot %₁₀ label₁₅) 12 TestMod.X -13 (call core._equiv_typedef %₁₂ %₇) -14 (gotoifnot %₁₃ label₁₈) -15 TestMod.X -16 (= slot₁/X %₁₅) -17 (goto label₂₀) -18 slot₁/X -19 (= TestMod.X %₁₈) -20 (goto label₂₃) -21 slot₁/X -22 (= TestMod.X %₂₁) -23 slot₁/X +13 (= slot₄/if_val (call core._equiv_typedef %₁₂ %₇)) +14 (goto label₁₆) +15 (= slot₄/if_val false) +16 slot₄/if_val +17 (gotoifnot %₁₆ label₂₁) +18 TestMod.X +19 (= slot₅/if_val %₁₈) +20 (goto label₂₂) +21 (= slot₅/if_val false) +22 slot₅/if_val +23 (gotoifnot %₁₆ label₂₄) 24 (call core.svec core.Any) -25 (call core._typebody! %₂₃ %₂₄) -26 (call core.svec) -27 (call core.svec) -28 (call JuliaLowering.eval_closure_type TestMod :#f##0 %₂₆ %₂₇) -29 TestMod.#f##0 -30 (new %₂₉) -31 slot₂/f -32 (call core.setfield! %₃₁ :contents %₃₀) -33 TestMod.#f##0 -34 (call core.svec %₃₃) -35 (call core.svec) -36 SourceLocation::3:5 -37 (call core.svec %₃₄ %₃₅ %₃₆) -38 --- method core.nothing %₃₇ +25 (call core._typebody! %₂₂ %₇ %₂₄) +26 (constdecl TestMod.X %₂₅) +27 (latestworld) +28 (call core.svec) +29 (call core.svec) +30 (call JuliaLowering.eval_closure_type TestMod :#f##0 %₂₈ %₂₉) +31 (latestworld) +32 TestMod.#f##0 +33 (new %₃₂) +34 slot₂/f +35 (call core.setfield! %₃₄ :contents %₃₃) +36 (latestworld) +37 TestMod.#f##0 +38 (call core.svec %₃₇) +39 (call core.svec) +40 SourceLocation::3:5 +41 (call core.svec %₃₈ %₃₉ %₄₀) +42 --- method core.nothing %₄₁ slots: [slot₁/#self#(!read)] 1 TestMod.X 2 (new %₁ 1) 3 (return %₂) -39 TestMod.X -40 (call core.apply_type core.Type %₃₉) -41 (call core.svec %₄₀) -42 (call core.svec) -43 SourceLocation::4:5 -44 (call core.svec %₄₁ %₄₂ %₄₃) -45 --- code_info +43 (latestworld) +44 (latestworld) +45 TestMod.X +46 (call core.apply_type core.Type %₄₅) +47 (call core.svec %₄₆) +48 (call core.svec) +49 SourceLocation::4:5 +50 (call core.svec %₄₇ %₄₈ %₄₉) +51 --- code_info slots: [slot₁/#ctor-self#(!read) slot₂/f(!read)] 1 (captured_local 1) 2 (call core.isdefined %₁ :contents) @@ -884,28 +933,32 @@ end 7 (call core.getfield %₁ :contents) 8 (call %₇) 9 (return %₈) -46 slot₂/f -47 (call core.svec %₄₆) -48 (call JuliaLowering.replace_captured_locals! %₄₅ %₄₇) -49 --- method core.nothing %₄₄ %₄₈ -50 TestMod.X -51 (call core.apply_type core.Type %₅₀) -52 (call core.svec %₅₁ core.Any) -53 (call core.svec) -54 SourceLocation::5:5 -55 (call core.svec %₅₂ %₅₃ %₅₄) -56 --- method core.nothing %₅₅ +52 slot₂/f +53 (call core.svec %₅₂) +54 (call JuliaLowering.replace_captured_locals! %₅₁ %₅₃) +55 --- method core.nothing %₅₀ %₅₄ +56 (latestworld) +57 (latestworld) +58 TestMod.X +59 (call core.apply_type core.Type %₅₈) +60 (call core.svec %₅₉ core.Any) +61 (call core.svec) +62 SourceLocation::5:5 +63 (call core.svec %₆₀ %₆₁ %₆₂) +64 --- method core.nothing %₆₃ slots: [slot₁/#ctor-self# slot₂/x] 1 slot₁/#ctor-self# 2 (new %₁ slot₂/x) 3 (return %₂) -57 TestMod.X -58 (call core.apply_type core.Type %₅₇) -59 (call core.svec %₅₈ core.Any core.Any) -60 (call core.svec) -61 SourceLocation::6:5 -62 (call core.svec %₅₉ %₆₀ %₆₁) -63 --- method core.nothing %₆₂ +65 (latestworld) +66 (latestworld) +67 TestMod.X +68 (call core.apply_type core.Type %₆₇) +69 (call core.svec %₆₈ core.Any core.Any) +70 (call core.svec) +71 SourceLocation::6:5 +72 (call core.svec %₆₉ %₇₀ %₇₁) +73 --- method core.nothing %₇₂ slots: [slot₁/#ctor-self# slot₂/y slot₃/z slot₄/tmp(!read)] 1 TestMod.ReallyXIPromise 2 slot₁/#ctor-self# @@ -921,21 +974,24 @@ end 12 (= slot₄/tmp (call core.typeassert %₁₁ %₁)) 13 slot₄/tmp 14 (return %₁₃) -64 TestMod.X -65 (call core.apply_type core.Type %₆₄) -66 (call core.svec %₆₅ core.Any core.Any core.Any) -67 (call core.svec) -68 SourceLocation::10:5 -69 (call core.svec %₆₆ %₆₇ %₆₈) -70 --- method core.nothing %₆₉ +74 (latestworld) +75 (latestworld) +76 TestMod.X +77 (call core.apply_type core.Type %₇₆) +78 (call core.svec %₇₇ core.Any core.Any core.Any) +79 (call core.svec) +80 SourceLocation::10:5 +81 (call core.svec %₇₈ %₇₉ %₈₀) +82 --- method core.nothing %₈₁ slots: [slot₁/#ctor-self# slot₂/a slot₃/b(!read) slot₄/c(!read)] 1 slot₁/#ctor-self# 2 (new %₁ slot₂/a) 3 (return %₂) -71 TestMod.X -72 (call core.apply_type core.Type %₇₁) -73 (call JuliaLowering.bind_docs! %₇₂ "Docs for X constructor\n" %₆₉) -74 (return core.nothing) +83 (latestworld) +84 TestMod.X +85 (call core.apply_type core.Type %₈₄) +86 (call JuliaLowering.bind_docs! %₈₅ "Docs for X constructor\n" %₈₁) +87 (return core.nothing) ######################################## # User defined inner constructors and helper functions for structs with type params @@ -948,7 +1004,7 @@ end #--------------------- 1 (newvar slot₅/f) 2 (global TestMod.X) -3 (const TestMod.X) +3 (latestworld) 4 (= slot₂/S (call core.TypeVar :S)) 5 (= slot₃/T (call core.TypeVar :T)) 6 slot₂/S @@ -959,76 +1015,84 @@ end 11 (call core._structtype TestMod :X %₈ %₉ %₁₀ false 1) 12 (= slot₄/X %₁₁) 13 (call core._setsuper! %₁₁ core.Any) -14 (isdefined TestMod.X) -15 (gotoifnot %₁₄ label₃₅) +14 (call core.isdefinedglobal TestMod :X false) +15 (gotoifnot %₁₄ label₁₉) 16 TestMod.X -17 (call core._equiv_typedef %₁₆ %₁₁) -18 (gotoifnot %₁₇ label₃₂) -19 TestMod.X -20 (= slot₄/X %₁₉) -21 TestMod.X -22 (call top.getproperty %₂₁ :body) -23 (call top.getproperty %₂₂ :body) -24 (call top.getproperty %₂₃ :parameters) -25 (call top.indexed_iterate %₂₄ 1) -26 (= slot₂/S (call core.getfield %₂₅ 1)) -27 (= slot₁/iterstate (call core.getfield %₂₅ 2)) -28 slot₁/iterstate -29 (call top.indexed_iterate %₂₄ 2 %₂₈) -30 (= slot₃/T (call core.getfield %₂₉ 1)) -31 (goto label₃₄) -32 slot₄/X -33 (= TestMod.X %₃₂) -34 (goto label₃₇) -35 slot₄/X -36 (= TestMod.X %₃₅) -37 slot₄/X +17 (= slot₈/if_val (call core._equiv_typedef %₁₆ %₁₁)) +18 (goto label₂₀) +19 (= slot₈/if_val false) +20 slot₈/if_val +21 (gotoifnot %₂₀ label₂₅) +22 TestMod.X +23 (= slot₉/if_val %₂₂) +24 (goto label₂₆) +25 (= slot₉/if_val false) +26 slot₉/if_val +27 (gotoifnot %₂₀ label₃₈) +28 TestMod.X +29 (call top.getproperty %₂₈ :body) +30 (call top.getproperty %₂₉ :body) +31 (call top.getproperty %₃₀ :parameters) +32 (call top.indexed_iterate %₃₁ 1) +33 (= slot₂/S (call core.getfield %₃₂ 1)) +34 (= slot₁/iterstate (call core.getfield %₃₂ 2)) +35 slot₁/iterstate +36 (call top.indexed_iterate %₃₁ 2 %₃₅) +37 (= slot₃/T (call core.getfield %₃₆ 1)) 38 (call core.svec core.Any) -39 (call core._typebody! %₃₇ %₃₈) -40 TestMod.X -41 TestMod.A -42 TestMod.B -43 (call core.apply_type %₄₀ %₄₁ %₄₂) -44 (call core.apply_type core.Type %₄₃) -45 (call core.svec %₄₄) -46 (call core.svec) -47 SourceLocation::3:5 -48 (call core.svec %₄₅ %₄₆ %₄₇) -49 --- method core.nothing %₄₈ +39 (call core._typebody! %₂₆ %₁₁ %₃₈) +40 (constdecl TestMod.X %₃₉) +41 (latestworld) +42 (latestworld) +43 TestMod.X +44 TestMod.A +45 TestMod.B +46 (call core.apply_type %₄₃ %₄₄ %₄₅) +47 (call core.apply_type core.Type %₄₆) +48 (call core.svec %₄₇) +49 (call core.svec) +50 SourceLocation::3:5 +51 (call core.svec %₄₈ %₄₉ %₅₀) +52 --- method core.nothing %₅₁ slots: [slot₁/#ctor-self#] 1 slot₁/#ctor-self# 2 (new %₁ 1) 3 (return %₂) -50 (= slot₆/U (call core.TypeVar :U)) -51 (= slot₇/V (call core.TypeVar :V)) -52 TestMod.X -53 slot₆/U -54 slot₇/V -55 (call core.apply_type %₅₂ %₅₃ %₅₄) -56 (call core.apply_type core.Type %₅₅) -57 (call core.svec %₅₆) +53 (latestworld) +54 (latestworld) +55 (= slot₆/U (call core.TypeVar :U)) +56 (= slot₇/V (call core.TypeVar :V)) +57 TestMod.X 58 slot₆/U 59 slot₇/V -60 (call core.svec %₅₈ %₅₉) -61 SourceLocation::4:5 -62 (call core.svec %₅₇ %₆₀ %₆₁) -63 --- method core.nothing %₆₂ +60 (call core.apply_type %₅₇ %₅₈ %₅₉) +61 (call core.apply_type core.Type %₆₀) +62 (call core.svec %₆₁) +63 slot₆/U +64 slot₇/V +65 (call core.svec %₆₃ %₆₄) +66 SourceLocation::4:5 +67 (call core.svec %₆₂ %₆₅ %₆₆) +68 --- method core.nothing %₆₇ slots: [slot₁/#ctor-self#] 1 slot₁/#ctor-self# 2 (new %₁ 1) 3 (return %₂) -64 (call core.svec) -65 (call core.svec) -66 (call JuliaLowering.eval_closure_type TestMod :#f##1 %₆₄ %₆₅) -67 TestMod.#f##1 -68 (new %₆₇) -69 (= slot₅/f %₆₈) -70 TestMod.#f##1 -71 (call core.svec %₇₀) -72 (call core.svec) -73 SourceLocation::5:5 -74 (call core.svec %₇₁ %₇₂ %₇₃) -75 --- method core.nothing %₇₄ +69 (latestworld) +70 (call core.svec) +71 (call core.svec) +72 (call JuliaLowering.eval_closure_type TestMod :#f##1 %₇₀ %₇₁) +73 (latestworld) +74 TestMod.#f##1 +75 (new %₇₄) +76 (= slot₅/f %₇₅) +77 (latestworld) +78 TestMod.#f##1 +79 (call core.svec %₇₈) +80 (call core.svec) +81 SourceLocation::5:5 +82 (call core.svec %₇₉ %₈₀ %₈₁) +83 --- method core.nothing %₈₂ slots: [slot₁/#self#(!read)] 1 TestMod.X 2 TestMod.A @@ -1036,7 +1100,8 @@ end 4 (call core.apply_type %₁ %₂ %₃) 5 (new %₄ 1) 6 (return %₅) -76 (return core.nothing) +84 (latestworld) +85 (return core.nothing) ######################################## # new() calls with splats; `Any` fields @@ -1047,42 +1112,46 @@ struct X end #--------------------- 1 (global TestMod.X) -2 (const TestMod.X) +2 (latestworld) 3 (call core.svec) 4 (call core.svec :x :y) 5 (call core.svec) 6 (call core._structtype TestMod :X %₃ %₄ %₅ false 2) 7 (= slot₁/X %₆) 8 (call core._setsuper! %₆ core.Any) -9 (isdefined TestMod.X) -10 (gotoifnot %₉ label₂₀) +9 (call core.isdefinedglobal TestMod :X false) +10 (gotoifnot %₉ label₁₄) 11 TestMod.X -12 (call core._equiv_typedef %₁₁ %₆) -13 (gotoifnot %₁₂ label₁₇) -14 TestMod.X -15 (= slot₁/X %₁₄) -16 (goto label₁₉) -17 slot₁/X -18 (= TestMod.X %₁₇) -19 (goto label₂₂) -20 slot₁/X -21 (= TestMod.X %₂₀) -22 slot₁/X +12 (= slot₂/if_val (call core._equiv_typedef %₁₁ %₆)) +13 (goto label₁₅) +14 (= slot₂/if_val false) +15 slot₂/if_val +16 (gotoifnot %₁₅ label₂₀) +17 TestMod.X +18 (= slot₃/if_val %₁₇) +19 (goto label₂₁) +20 (= slot₃/if_val false) +21 slot₃/if_val +22 (gotoifnot %₁₅ label₂₃) 23 (call core.svec core.Any core.Any) -24 (call core._typebody! %₂₂ %₂₃) -25 TestMod.X -26 (call core.apply_type core.Type %₂₅) -27 (call core.svec %₂₆ core.Any) -28 (call core.svec) -29 SourceLocation::4:5 -30 (call core.svec %₂₇ %₂₈ %₂₉) -31 --- method core.nothing %₃₀ +24 (call core._typebody! %₂₁ %₆ %₂₃) +25 (constdecl TestMod.X %₂₄) +26 (latestworld) +27 (latestworld) +28 TestMod.X +29 (call core.apply_type core.Type %₂₈) +30 (call core.svec %₂₉ core.Any) +31 (call core.svec) +32 SourceLocation::4:5 +33 (call core.svec %₃₀ %₃₁ %₃₂) +34 --- method core.nothing %₃₃ slots: [slot₁/#ctor-self# slot₂/xs] 1 slot₁/#ctor-self# 2 (call core._apply_iterate top.iterate core.tuple slot₂/xs) 3 (splatnew %₁ %₂) 4 (return %₃) -32 (return core.nothing) +35 (latestworld) +36 (return core.nothing) ######################################## # new() calls with splats; typed fields @@ -1093,7 +1162,7 @@ struct X{T} end #--------------------- 1 (global TestMod.X) -2 (const TestMod.X) +2 (latestworld) 3 (= slot₁/T (call core.TypeVar :T)) 4 slot₁/T 5 (call core.svec %₄) @@ -1102,40 +1171,43 @@ end 8 (call core._structtype TestMod :X %₅ %₆ %₇ false 2) 9 (= slot₂/X %₈) 10 (call core._setsuper! %₈ core.Any) -11 (isdefined TestMod.X) -12 (gotoifnot %₁₁ label₂₇) +11 (call core.isdefinedglobal TestMod :X false) +12 (gotoifnot %₁₁ label₁₆) 13 TestMod.X -14 (call core._equiv_typedef %₁₃ %₈) -15 (gotoifnot %₁₄ label₂₄) -16 TestMod.X -17 (= slot₂/X %₁₆) -18 TestMod.X -19 (call top.getproperty %₁₈ :body) -20 (call top.getproperty %₁₉ :parameters) -21 (call top.indexed_iterate %₂₀ 1) -22 (= slot₁/T (call core.getfield %₂₁ 1)) -23 (goto label₂₆) -24 slot₂/X -25 (= TestMod.X %₂₄) -26 (goto label₂₉) -27 slot₂/X -28 (= TestMod.X %₂₇) -29 slot₂/X +14 (= slot₄/if_val (call core._equiv_typedef %₁₃ %₈)) +15 (goto label₁₇) +16 (= slot₄/if_val false) +17 slot₄/if_val +18 (gotoifnot %₁₇ label₂₂) +19 TestMod.X +20 (= slot₅/if_val %₁₉) +21 (goto label₂₃) +22 (= slot₅/if_val false) +23 slot₅/if_val +24 (gotoifnot %₁₇ label₃₀) +25 TestMod.X +26 (call top.getproperty %₂₅ :body) +27 (call top.getproperty %₂₆ :parameters) +28 (call top.indexed_iterate %₂₇ 1) +29 (= slot₁/T (call core.getfield %₂₈ 1)) 30 slot₁/T 31 TestMod.A 32 (call core.svec %₃₀ %₃₁) -33 (call core._typebody! %₂₉ %₃₂) -34 (= slot₃/T (call core.TypeVar :T)) -35 TestMod.X -36 slot₃/T -37 (call core.apply_type %₃₅ %₃₆) -38 (call core.apply_type core.Type %₃₇) -39 (call core.svec %₃₈ core.Any) -40 slot₃/T -41 (call core.svec %₄₀) -42 SourceLocation::4:5 -43 (call core.svec %₃₉ %₄₁ %₄₂) -44 --- method core.nothing %₄₃ +33 (call core._typebody! %₂₃ %₈ %₃₂) +34 (constdecl TestMod.X %₃₃) +35 (latestworld) +36 (latestworld) +37 (= slot₃/T (call core.TypeVar :T)) +38 TestMod.X +39 slot₃/T +40 (call core.apply_type %₃₈ %₃₉) +41 (call core.apply_type core.Type %₄₀) +42 (call core.svec %₄₁ core.Any) +43 slot₃/T +44 (call core.svec %₄₃) +45 SourceLocation::4:5 +46 (call core.svec %₄₂ %₄₄ %₄₅) +47 --- method core.nothing %₄₆ slots: [slot₁/#ctor-self# slot₂/xs slot₃/tmp slot₄/tmp] 1 (call core._apply_iterate top.iterate core.tuple slot₂/xs) 2 (call core.nfields %₁) @@ -1168,7 +1240,8 @@ end 29 slot₄/tmp 30 (new %₁₁ %₂₀ %₂₉) 31 (return %₃₀) -45 (return core.nothing) +48 (latestworld) +49 (return core.nothing) ######################################## # Error: new doesn't accept keywords From dda8afd589cfae9961fde4afcd0b3dc2d38b63bc Mon Sep 17 00:00:00 2001 From: Em Chu Date: Wed, 25 Jun 2025 09:51:11 -0700 Subject: [PATCH 16/35] Update README to known-good julia, JuliaSyntax versions Latest julia works. Changes are needed to work with the latest JuliaSyntax, but that isn't in base julia yet, and more changes are likely to come. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 789e1ce7..47ea97db 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ This work is intended to Note this is a work in progress; many types of syntax are not yet handled. -1. You need a 1.12-DEV build of Julia: At least 1.12.0-DEV.512. Commit `263928f9ad4` is currentl known to work. Note that JuliaLowering relies on Julia internals and may be broken on the latest Julia dev version from time to time. (In fact it is currently broken on the latest `1.12-DEV`.) -2. Check out the main branch of [JuliaSyntax](https://github.com/JuliaLang/JuliaSyntax.jl) +1. You need a 1.13.0-DEV build of Julia: At least 1.13.0-DEV.880. Commit `5ebc5b463ea` is currently known to work. Note that JuliaLowering relies on Julia internals and may be broken on the latest Julia dev version from time to time. +2. Use commit `46723f0` of [JuliaSyntax](https://github.com/JuliaLang/JuliaSyntax.jl) 3. Get the latest version of [JuliaSyntaxFormatter](https://github.com/c42f/JuliaSyntaxFormatter.jl) 4. Run the demo `include("test/demo.jl")` From 08f101ad5493b3399751dd47ea80c76b9fc52991 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Tue, 29 Jul 2025 12:38:43 -0700 Subject: [PATCH 17/35] Fix small bug from #16 so tests pass The change lifted the scope of `note`, so it was being changed in the loop --- src/utils.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/utils.jl b/src/utils.jl index 5d749f05..b6f9e834 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -47,12 +47,12 @@ function showprov(io::IO, exs::AbstractVector; print(io, "\n\n") end k = kind(ex) - if isnothing(note) # use provided `note` otherwise - note = i > 1 && k == K"macrocall" ? "in macro expansion" : - i > 1 && k == K"$" ? "interpolated here" : - "in source" + if isnothing(note) + fallback_note = i > 1 && k == K"macrocall" ? "in macro expansion" : + i > 1 && k == K"$" ? "interpolated here" : + "in source" end - highlight(io, sr; note=note, highlight_kwargs...) + highlight(io, sr; note=something(note, fallback_note), highlight_kwargs...) if include_location line, _ = source_location(sr) From 50bd7e475b5872382259d52d4bf2685eb6ab81ed Mon Sep 17 00:00:00 2001 From: Em Chu Date: Wed, 30 Jul 2025 11:21:41 -0700 Subject: [PATCH 18/35] Changes from code review: const/global lowering Ping me if you'd like this squashed into the original const/global commit! Co-authored-by: Claire Foster --- src/closure_conversion.jl | 12 ++-- src/desugaring.jl | 129 +++++++++++++------------------------- src/kinds.jl | 2 +- src/linear_ir.jl | 5 +- src/scope_analysis.jl | 13 ++-- test/decls.jl | 46 +++++++++++--- test/decls_ir.jl | 10 +-- 7 files changed, 102 insertions(+), 115 deletions(-) diff --git a/src/closure_conversion.jl b/src/closure_conversion.jl index cbcdf16b..79bde082 100644 --- a/src/closure_conversion.jl +++ b/src/closure_conversion.jl @@ -352,11 +352,13 @@ function _convert_closures(ctx::ClosureConversionCtx, ex) @assert kind(ex[1]) == K"BindingId" binfo = lookup_binding(ctx, ex[1]) if binfo.kind == :global - @ast ctx ex [ - K"globaldecl" - ex[1] - _convert_closures(ctx, ex[2]) - ] + @ast ctx ex [K"block" + # flisp has this, but our K"assert" handling is in a previous pass + # [K"assert" "toplevel_only"::K"Symbol" [K"inert" ex]] + [K"globaldecl" + ex[1] + _convert_closures(ctx, ex[2])] + "nothing"::K"core"] else makeleaf(ctx, ex, K"TOMBSTONE") end diff --git a/src/desugaring.jl b/src/desugaring.jl index 4e4c1b9b..8e5220f3 100644 --- a/src/desugaring.jl +++ b/src/desugaring.jl @@ -814,8 +814,7 @@ function expand_generator(ctx, ex) outervars_by_key = Dict{NameKey,typeof(ex)}() for iterspecs in ex[2:end-1] for iterspec in children(iterspecs) - lhs = iterspec[1] - foreach_lhs_var(lhs) do var + for var in lhs_bound_names(iterspec[1]) @assert kind(var) == K"Identifier" # Todo: K"BindingId"? outervars_by_key[NameKey(var)] = var end @@ -1170,15 +1169,13 @@ function expand_unionall_def(ctx, srcref, lhs, rhs, is_const=true) throw(LoweringError(lhs, "empty type parameter list in type alias")) end name = lhs[1] - rr = ssavar(ctx, srcref) expand_forms_2( ctx, - @ast ctx srcref [ - K"block" - [K"=" rr [K"where" rhs lhs[2:end]...]] - [is_const ? K"constdecl" : K"assign_const_if_global" name rr] + @ast ctx srcref [K"block" + rr := [K"where" rhs lhs[2:end]...] + [is_const ? K"constdecl" : K"assign_or_constdecl_if_global" name rr] [K"latestworld_if_toplevel"] - rr + [K"removable" rr] ] ) end @@ -1229,10 +1226,8 @@ function expand_assignment(ctx, ex, is_const=false) ) elseif is_identifier_like(lhs) if is_const - rr = ssavar(ctx, rhs) - @ast ctx ex [ - K"block" - sink_assignment(ctx, ex, rr, expand_forms_2(ctx, rhs)) + @ast ctx ex [K"block" + rr := expand_forms_2(ctx, rhs) [K"constdecl" lhs rr] [K"latestworld"] [K"removable" rr] @@ -1276,11 +1271,10 @@ function expand_assignment(ctx, ex, is_const=false) x = lhs[1] T = lhs[2] res = if is_const - expand_forms_2(ctx, @ast ctx ex [ - K"const" + expand_forms_2(ctx, @ast ctx ex [K"const" [K"=" - lhs[1] - convert_for_type_decl(ctx, ex, rhs, T, true) + lhs[1] + convert_for_type_decl(ctx, ex, rhs, T, true) ]]) elseif is_identifier_like(x) # Identifer in lhs[1] is a variable type declaration, eg @@ -1467,7 +1461,7 @@ function expand_let(ctx, ex) ] elseif kind(lhs) == K"tuple" lhs_locals = SyntaxList(ctx) - foreach_lhs_var(lhs) do var + for var in lhs_bound_names(lhs) push!(lhs_locals, @ast ctx var [K"local" var]) push!(lhs_locals, @ast ctx var [K"always_defined" var]) end @@ -1904,23 +1898,6 @@ end #------------------------------------------------------------------------------- # Expand for loops -# Extract the variable names assigned to from a "fancy assignment left hand -# side" such as nested tuple destructuring. -function foreach_lhs_var(f::Function, ex) - k = kind(ex) - if k == K"Identifier" || k == K"BindingId" - f(ex) - elseif k == K"::" && numchildren(ex) == 2 - foreach_lhs_var(f, ex[1]) - elseif k == K"tuple" || k == K"parameters" - for e in children(ex) - foreach_lhs_var(f, e) - end - end - # k == K"Placeholder" ignored, along with everything else - we assume - # validation is done elsewhere. -end - function expand_for(ctx, ex) iterspecs = ex[1] @@ -1936,7 +1913,7 @@ function expand_for(ctx, ex) @chk kind(iterspec) == K"in" lhs = iterspec[1] if kind(lhs) != K"outer" - foreach_lhs_var(lhs) do var + for var in lhs_bound_names(lhs) push!(copied_vars, @ast ctx var [K"=" var var]) end end @@ -1953,7 +1930,7 @@ function expand_for(ctx, ex) if outer lhs = lhs[1] end - foreach_lhs_var(lhs) do var + for var in lhs_bound_names(lhs) if outer push!(lhs_outer_defs, @ast ctx var var) else @@ -2108,7 +2085,7 @@ end # (x::T, (y::U, z)) # strip out stmts = (local x) (decl x T) (local x) (decl y U) (local z) # and return (x, (y, z)) -function strip_decls!(ctx, stmts, declkind, declkind2, declmeta, ex) +function strip_decls!(ctx, stmts, declkind, declmeta, ex) k = kind(ex) if k == K"Identifier" if !isnothing(declmeta) @@ -2116,9 +2093,6 @@ function strip_decls!(ctx, stmts, declkind, declkind2, declmeta, ex) else push!(stmts, makenode(ctx, ex, declkind, ex)) end - if !isnothing(declkind2) - push!(stmts, makenode(ctx, ex, declkind2, ex)) - end ex elseif k == K"Placeholder" ex @@ -2127,40 +2101,34 @@ function strip_decls!(ctx, stmts, declkind, declkind2, declmeta, ex) name = ex[1] @chk kind(name) == K"Identifier" push!(stmts, makenode(ctx, ex, K"decl", name, ex[2])) - strip_decls!(ctx, stmts, declkind, declkind2, declmeta, ex[1]) + strip_decls!(ctx, stmts, declkind, declmeta, ex[1]) elseif k == K"tuple" || k == K"parameters" cs = SyntaxList(ctx) for e in children(ex) - push!(cs, strip_decls!(ctx, stmts, declkind, declkind2, declmeta, e)) + push!(cs, strip_decls!(ctx, stmts, declkind, declmeta, e)) end makenode(ctx, ex, k, cs) + else + throw(LoweringError(ex, "invalid kind $k in $declkind declaration")) end end +# Separate decls and assignments (which require re-expansion) # local x, (y=2), z ==> local x; local z; y = 2 -# Note there are differences from lisp (evaluation order?) -function expand_decls(ctx, ex) +function expand_decls(ctx, ex, is_const=false) declkind = kind(ex) + @assert declkind in KSet"local global" declmeta = get(ex, :meta, nothing) - if numchildren(ex) == 1 && kind(ex[1]) ∈ KSet"const global local" - declkind2 = kind(ex[1]) - bindings = children(ex[1]) - else - declkind2 = nothing - bindings = children(ex) - end + bindings = children(ex) stmts = SyntaxList(ctx) for binding in bindings kb = kind(binding) if is_prec_assignment(kb) @chk numchildren(binding) == 2 - lhs = strip_decls!(ctx, stmts, declkind, declkind2, declmeta, binding[1]) - push!(stmts, @ast ctx binding [kb lhs binding[2]]) - elseif is_sym_decl(binding) - if declkind == K"const" || declkind2 == K"const" - throw(LoweringError(ex, "expected assignment after `const`")) - end - strip_decls!(ctx, stmts, declkind, declkind2, declmeta, binding) + lhs = strip_decls!(ctx, stmts, declkind, declmeta, binding[1]) + push!(stmts, expand_assignment(ctx, @ast ctx binding [kb lhs binding[2]])) + elseif is_sym_decl(binding) && !is_const + strip_decls!(ctx, stmts, declkind, declmeta, binding) else throw(LoweringError(ex, "invalid syntax in variable declaration")) end @@ -2168,49 +2136,37 @@ function expand_decls(ctx, ex) makenode(ctx, ex, K"block", stmts) end -# Return all the names that will be bound by the assignment LHS, including -# curlies and calls. -function lhs_bound_names(ex) +# Extract the variable names assigned to from a "fancy assignment left hand +# side" such as nested tuple destructuring, curlies, and calls. +function lhs_bound_names(ex, out=SyntaxList(ex)) k = kind(ex) if k == K"Placeholder" - [] + # Ignored elseif is_identifier_like(ex) - [ex] - elseif k in KSet"call curly where ::" - lhs_bound_names(ex[1]) + push!(out, ex) + elseif (k === K"::" && numchildren(ex) === 2) || k in KSet"call curly where" + lhs_bound_names(ex[1], out) elseif k in KSet"tuple parameters" - vcat(map(lhs_bound_names, children(ex))...) - else - [] + map(c->lhs_bound_names(c, out), children(ex)) end + return out end function expand_const_decl(ctx, ex) - function check_assignment(asgn) - @chk (kind(asgn) == K"=") (ex, "expected assignment after `const`") - end - k = kind(ex[1]) - if numchildren(ex) == 2 - @ast ctx ex [ - K"constdecl" - ex[1] - expand_forms_2(ctx, ex[2]) - ] - elseif k == K"global" + if k == K"global" asgn = ex[1][1] - check_assignment(asgn) + @chk (kind(asgn) == K"=") (ex, "expected assignment after `const`") globals = map(lhs_bound_names(asgn[1])) do x @ast ctx ex [K"global" x] end - @ast ctx ex [ - K"block" + @ast ctx ex [K"block" globals... - expand_assignment(ctx, ex[1], true) + expand_assignment(ctx, asgn, true) ] elseif k == K"=" if numchildren(ex[1]) >= 1 && kind(ex[1][1]) == K"tuple" - throw(LoweringError(ex[1][1], "unsupported `const` tuple")) + TODO(ex[1][1], "`const` tuple assignment desugaring") end expand_assignment(ctx, ex[1], true) elseif k == K"local" @@ -4403,8 +4359,11 @@ function expand_forms_2(ctx::DesugaringContext, ex::SyntaxTree, docs=nothing) if numchildren(ex) == 1 && kind(ex[1]) == K"Identifier" # Don't recurse when already simplified - `local x`, etc ex + elseif k == K"global" && kind(ex[1]) == K"const" + # Normalize `global const` to `const global` + expand_const_decl(ctx, @ast ctx ex [K"const" [K"global" ex[1][1]]]) else - expand_forms_2(ctx, expand_decls(ctx, ex)) + expand_decls(ctx, ex) end elseif k == K"where" expand_forms_2(ctx, expand_wheres(ctx, ex)) diff --git a/src/kinds.jl b/src/kinds.jl index 0714f1d6..741307ba 100644 --- a/src/kinds.jl +++ b/src/kinds.jl @@ -96,7 +96,7 @@ function _register_kinds() "_opaque_closure" # The enclosed statements must be executed at top level "toplevel_butfirst" - "assign_const_if_global" + "assign_or_constdecl_if_global" "moved_local" "label" "trycatchelse" diff --git a/src/linear_ir.jl b/src/linear_ir.jl index 0ac56ce4..d356d2f7 100644 --- a/src/linear_ir.jl +++ b/src/linear_ir.jl @@ -332,7 +332,7 @@ function emit_assignment_or_setglobal(ctx, srcref, lhs, rhs, op=K"=") if binfo.kind == :global && op == K"=" emit(ctx, @ast ctx srcref [ K"call" - "setglobal!"::K"top" + "setglobal!"::K"core" binfo.mod::K"Value" binfo.name::K"Symbol" rhs @@ -884,8 +884,7 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos) if numchildren(ex) == 1 || is_identifier_like(ex[2]) emit(ctx, ex) else - rr = ssavar(ctx, ex[2]) - emit(ctx, @ast ctx ex [K"=" rr ex[2]]) + rr = emit_assign_tmp(ctx, ex[2]) emit(ctx, @ast ctx ex [K"globaldecl" ex[1] rr]) end ctx.is_toplevel_thunk && emit(ctx, makenode(ctx, ex, K"latestworld")) diff --git a/src/scope_analysis.jl b/src/scope_analysis.jl index 59314149..38e8e23a 100644 --- a/src/scope_analysis.jl +++ b/src/scope_analysis.jl @@ -44,7 +44,7 @@ function _find_scope_vars!(ctx, assignments, locals, destructured_args, globals, end elseif k == K"global" _insert_if_not_present!(globals, NameKey(ex[1]), ex) - elseif k == K"assign_const_if_global" + elseif k == K"assign_or_constdecl_if_global" # like v = val, except that if `v` turns out global(either implicitly or # by explicit `global`), it gains an implicit `const` _insert_if_not_present!(assignments, NameKey(ex[1]), ex) @@ -565,15 +565,14 @@ function _resolve_scopes(ctx, ex::SyntaxTree) end end resolved - elseif k == K"assign_const_if_global" + elseif k == K"assign_or_constdecl_if_global" id = _resolve_scopes(ctx, ex[1]) bk = lookup_binding(ctx, id).kind - if bk == :local && numchildren(ex) != 1 - @ast ctx ex _resolve_scopes(ctx, [K"=" children(ex)...]) - elseif bk != :local # TODO: should this be == :global? - @ast ctx ex _resolve_scopes(ctx, [K"constdecl" children(ex)...]) + @assert numchildren(ex) === 2 + if bk == :global + @ast ctx ex _resolve_scopes(ctx, [K"constdecl" ex[1] ex[2]]) else - makeleaf(ctx, ex, K"TOMBSTONE") + @ast ctx ex _resolve_scopes(ctx, [K"=" ex[1] ex[2]]) end else mapchildren(e->_resolve_scopes(ctx, e), ctx, ex) diff --git a/test/decls.jl b/test/decls.jl index f56e7d3b..8866b303 100644 --- a/test/decls.jl +++ b/test/decls.jl @@ -9,7 +9,7 @@ begin end """) === 1 -# In value position, yeild the right hand side, not `x` +# In value position, yield the right hand side, not `x` @test JuliaLowering.include_string(test_mod, """ local x::Int = 1.0 """) === 1.0 @@ -33,6 +33,29 @@ let end """) === (1, 20) +# Global const mixes +@test JuliaLowering.include_string(test_mod, "global x_g = 1") === 1 +@test Base.isdefinedglobal(test_mod, :x_g) +@test !Base.isconst(test_mod, :x_g) +@test test_mod.x_g === 1 + +@test JuliaLowering.include_string(test_mod, "const x_c = 1") === 1 +@test Base.isdefinedglobal(test_mod, :x_c) +@test Base.isconst(test_mod, :x_c) +@test test_mod.x_c === 1 + +@test JuliaLowering.include_string(test_mod, "global const x_gc = 1") === 1 +@test Base.isdefinedglobal(test_mod, :x_gc) +@test Base.isconst(test_mod, :x_gc) +@test test_mod.x_gc === 1 + +@test JuliaLowering.include_string(test_mod, "const global x_cg = 1") === 1 +@test Base.isdefinedglobal(test_mod, :x_cg) +@test Base.isconst(test_mod, :x_cg) +@test test_mod.x_cg === 1 +# Possibly worth testing excessive global/const keywords once we decide whether +# that's a parse error or a lowering error + # Global decls with types @test JuliaLowering.include_string(test_mod, """ global a_typed_global::Int = 10.0 @@ -49,16 +72,21 @@ end @test Core.get_binding_type(test_mod, :a_typed_global_2) === Int @test test_mod.a_typed_global_2 === 10 -# Const and tuple assignments -@test JuliaLowering.include_string(test_mod, "(a0, a1, a2) = [1,2,3]") == [1,2,3] +@test JuliaLowering.include_string(test_mod, "const x_c_T::Int = 9") === 9 +@test Base.isdefinedglobal(test_mod, :x_c_T) +@test Base.isconst(test_mod, :x_c_T) + +@testset "typed const redeclaration" begin + # redeclaration of the same value used to be allowed + @test_throws ErrorException JuliaLowering.include_string(test_mod, "x_c_T = 9") + @test_throws ErrorException JuliaLowering.include_string(test_mod, "x_c_T = 10") + # redeclaration with const should be OK + @test JuliaLowering.include_string(test_mod, "const x_c_T::Int = 0") === 0 +end -@test JuliaLowering.include_string(test_mod, "const abc::Int = 9") === 9 +# Tuple/destructuring assignments +@test JuliaLowering.include_string(test_mod, "(a0, a1, a2) = [1,2,3]") == [1,2,3] -# redeclaration of the same value used to be allowed -@test_throws ErrorException JuliaLowering.include_string(test_mod, "abc = 9") -@test_throws ErrorException JuliaLowering.include_string(test_mod, "abc = 10") -# redeclaration with const should be OK -@test JuliaLowering.include_string(test_mod, "const abc::Int = 0") === 0 # Unsupported for now @test_throws LoweringError JuliaLowering.include_string(test_mod, "const a,b,c = 1,2,3") diff --git a/test/decls_ir.jl b/test/decls_ir.jl index 30848d48..444fbdaa 100644 --- a/test/decls_ir.jl +++ b/test/decls_ir.jl @@ -50,7 +50,7 @@ const xxx,xxxx,xxxxx = 10,20,30 #--------------------- LoweringError: const xxx,xxxx,xxxxx = 10,20,30 -# └─────────────┘ ── unsupported `const` tuple +# └─────────────┘ ── Lowering TODO: `const` tuple assignment desugaring ######################################## # Const in chain: only first is const @@ -69,7 +69,7 @@ const c0 = v0 = v1 = 123 11 slot₁/tmp 12 (= slot₁/tmp (call top.convert %₅ %₁₁)) 13 slot₁/tmp -14 (call top.setglobal! TestMod :v0 %₁₃) +14 (call core.setglobal! TestMod :v0 %₁₃) 15 (globaldecl TestMod.v1) 16 (latestworld) 17 (call core.get_binding_type TestMod :v1) @@ -81,7 +81,7 @@ const c0 = v0 = v1 = 123 23 slot₂/tmp 24 (= slot₂/tmp (call top.convert %₁₇ %₂₃)) 25 slot₂/tmp -26 (call top.setglobal! TestMod :v1 %₂₅) +26 (call core.setglobal! TestMod :v1 %₂₅) 27 (return %₁) ######################################## @@ -99,7 +99,7 @@ xx = 10 9 slot₁/tmp 10 (= slot₁/tmp (call top.convert %₃ %₉)) 11 slot₁/tmp -12 (call top.setglobal! TestMod :xx %₁₁) +12 (call core.setglobal! TestMod :xx %₁₁) 13 (return 10) ######################################## @@ -121,7 +121,7 @@ global xx::T = 10 13 slot₁/tmp 14 (= slot₁/tmp (call top.convert %₇ %₁₃)) 15 slot₁/tmp -16 (call top.setglobal! TestMod :xx %₁₅) +16 (call core.setglobal! TestMod :xx %₁₅) 17 (return 10) ######################################## From ddfa8f1763ba317f5957b0f74689a06ee2b4d34e Mon Sep 17 00:00:00 2001 From: Em Chu Date: Thu, 31 Jul 2025 09:40:16 -0700 Subject: [PATCH 19/35] Changes from code review Co-authored-by: Claire Foster --- src/desugaring.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desugaring.jl b/src/desugaring.jl index 8e5220f3..da0b0bec 100644 --- a/src/desugaring.jl +++ b/src/desugaring.jl @@ -3811,7 +3811,7 @@ function insert_struct_shim(ctx, fieldtypes, name) ex[2].name_val == name.name_val @ast ctx ex [K"call" "struct_name_shim"::K"core" ex[1] ex[2] ctx.mod::K"Value" name] elseif numchildren(ex) > 0 - @ast ctx ex [ex.kind map(replace_type, children(ex))...] + mapchildren(replace_type, ctx, ex) else ex end From c1242d1accd14a635d51f248c33b112db81c7be3 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Thu, 31 Jul 2025 15:03:18 -0700 Subject: [PATCH 20/35] Remove a special case No longer needed since we no longer put `global` or `local` forms back into the expand_forms machine. Some error messages change slightly as a result. --- src/desugaring.jl | 5 +---- test/scopes_ir.jl | 16 ++++++++-------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/desugaring.jl b/src/desugaring.jl index da0b0bec..80f93d06 100644 --- a/src/desugaring.jl +++ b/src/desugaring.jl @@ -4356,10 +4356,7 @@ function expand_forms_2(ctx::DesugaringContext, ex::SyntaxTree, docs=nothing) elseif k == K"const" expand_const_decl(ctx, ex) elseif k == K"local" || k == K"global" - if numchildren(ex) == 1 && kind(ex[1]) == K"Identifier" - # Don't recurse when already simplified - `local x`, etc - ex - elseif k == K"global" && kind(ex[1]) == K"const" + if k == K"global" && kind(ex[1]) == K"const" # Normalize `global const` to `const global` expand_const_decl(ctx, @ast ctx ex [K"const" [K"global" ex[1][1]]]) else diff --git a/test/scopes_ir.jl b/test/scopes_ir.jl index 9fd6b826..b40fbf92 100644 --- a/test/scopes_ir.jl +++ b/test/scopes_ir.jl @@ -276,7 +276,7 @@ LoweringError: let local x global x -# └──────┘ ── Variable `x` declared both local and global +# ╙ ── Variable `x` declared both local and global end ######################################## @@ -288,7 +288,7 @@ end LoweringError: function f(x) local x -# └─────┘ ── local variable name `x` conflicts with an argument +# ╙ ── local variable name `x` conflicts with an argument end ######################################## @@ -300,7 +300,7 @@ end LoweringError: function f(x) global x -# └──────┘ ── global variable name `x` conflicts with an argument +# ╙ ── global variable name `x` conflicts with an argument end ######################################## @@ -313,7 +313,7 @@ end LoweringError: function f((x,)) global x -# └──────┘ ── Variable `x` declared both local and global +# ╙ ── Variable `x` declared both local and global end ######################################## @@ -325,7 +325,7 @@ end LoweringError: function f(::T) where T local T -# └─────┘ ── local variable name `T` conflicts with a static parameter +# ╙ ── local variable name `T` conflicts with a static parameter end ######################################## @@ -337,7 +337,7 @@ end LoweringError: function f(::T) where T global T -# └──────┘ ── global variable name `T` conflicts with a static parameter +# ╙ ── global variable name `T` conflicts with a static parameter end ######################################## @@ -352,7 +352,7 @@ LoweringError: function f(::T) where T let local T -# └─────┘ ── local variable name `T` conflicts with a static parameter +# ╙ ── local variable name `T` conflicts with a static parameter end end @@ -368,7 +368,7 @@ LoweringError: function f(::T) where T let global T -# └──────┘ ── global variable name `T` conflicts with a static parameter +# ╙ ── global variable name `T` conflicts with a static parameter end end From 56422aa02bc62f2fa500e723508f035faa26825e Mon Sep 17 00:00:00 2001 From: Em Chu Date: Fri, 27 Jun 2025 09:12:05 -0700 Subject: [PATCH 21/35] Conversion from Expr and JuliaSyntax bump --- src/JuliaLowering.jl | 3 +- src/compat.jl | 384 +++++++++++++++++++++++++++++++++++++++++++ src/desugaring.jl | 21 +-- src/syntax_graph.jl | 26 +-- test/compat.jl | 373 +++++++++++++++++++++++++++++++++++++++++ test/functions_ir.jl | 4 +- 6 files changed, 783 insertions(+), 28 deletions(-) create mode 100644 src/compat.jl create mode 100644 test/compat.jl diff --git a/src/JuliaLowering.jl b/src/JuliaLowering.jl index a365a9e6..2f614c25 100644 --- a/src/JuliaLowering.jl +++ b/src/JuliaLowering.jl @@ -13,7 +13,7 @@ using JuliaSyntax: highlight, Kind, @KSet_str using JuliaSyntax: is_leaf, children, numchildren, head, kind, flags, has_flags, numeric_flags using JuliaSyntax: filename, first_byte, last_byte, byte_range, sourcefile, source_location, span, sourcetext -using JuliaSyntax: is_literal, is_number, is_operator, is_prec_assignment, is_prefix_call, is_infix_op_call, is_postfix_op_call, is_error, is_dotted +using JuliaSyntax: is_literal, is_number, is_operator, is_prec_assignment, is_prefix_call, is_infix_op_call, is_postfix_op_call, is_error _include("kinds.jl") _register_kinds() @@ -32,6 +32,7 @@ _include("runtime.jl") _include("syntax_macros.jl") _include("eval.jl") +_include("compat.jl") function __init__() _register_kinds() diff --git a/src/compat.jl b/src/compat.jl new file mode 100644 index 00000000..cc56acaa --- /dev/null +++ b/src/compat.jl @@ -0,0 +1,384 @@ +const JS = JuliaSyntax + +function _insert_tree_node(graph::SyntaxGraph, k::JuliaSyntax.Kind, + src::SourceAttrType, flags::UInt16=0x0000) + id = newnode!(graph) + sethead!(graph, id, k) + setattr!(graph, id, source=src) + setflags!(graph, id, flags) + return id +end + +""" +An Expr -> SyntaxTree transformation that should preserve semantics, but will +have low-quality provenance info (namely, each tree node will be associated with +the last seen LineNumberNode in the pre-order expr traversal). + +Last-resort option so that, for example, we can lower the output of old +Expr-producing macros. Always prefer re-parsing source text over using this. + +Does not support lowered exprs. +""" +function expr_to_syntaxtree(@nospecialize(e), lnn::Union{LineNumberNode, Nothing}=nothing) + graph = SyntaxGraph() + ensure_attributes!(graph, + kind=Kind, syntax_flags=UInt16, + source=SourceAttrType, var_id=Int, value=Any, + name_val=String, is_toplevel_thunk=Bool) + toplevel_src = if isnothing(lnn) + # Provenance sinkhole for all nodes until we hit a linenode + dummy_src = SourceRef( + SourceFile("No source for expression $e"), + 1, JuliaSyntax.GreenNode(K"None", 0)) + _insert_tree_node(graph, K"None", dummy_src) + else + lnn + end + st_id, _ = _insert_convert_expr(e, graph, toplevel_src) + out = SyntaxTree(graph, st_id) + return out +end + +function _expr_replace!(@nospecialize(e), replace_pred::Function, replacer!::Function, + recurse_pred=(@nospecialize e)->true) + if replace_pred(e) + replacer!(e) + end + if e isa Expr && recurse_pred(e) + for a in e.args + _expr_replace!(a, replace_pred, replacer!, recurse_pred) + end + end +end + +function _to_iterspec(exs::Vector) + if length(exs) === 1 && exs[1].head === :filter + @assert length(exs[1].args) >= 2 + return Expr(:filter, _to_iterspec(exs[1].args[2:end]), exs[1].args[1]) + end + outex = Expr(:iteration) + for e in exs + if e.head === :block + for iter in e.args + push!(outex.args, Expr(:in, iter.args...)) + end + elseif e.head === :(=) + push!(outex.args, Expr(:in, e.args...)) + else + @assert false "unknown iterspec in $e" + end + end + return outex +end + +""" +Return `e.args`, but with any parameters in SyntaxTree (flattened, source) order. +Parameters are expected to be as `e.args[pos]`. + +e.g. orderings of (a,b,c;d;e;f): + Expr: (tuple (parameters (parameters (parameters f) e) d) a b c) + SyntaxTree: (tuple a b c (parameters d) (parameters e) (parameters f)) +""" +function collect_expr_parameters(e::Expr, pos::Int) + params = expr_parameters(e, pos) + isnothing(params) && return e.args + args = Any[e.args[1:pos-1]..., e.args[pos+1:end]...] + return _flatten_params(params, args) +end +function _flatten_params(p::Expr, out::Vector{Any}) + p1 = expr_parameters(p, 1) + if !isnothing(p1) + push!(out, Expr(:parameters, p.args[2:end]...)) + _flatten_params(p1, out) + else + push!(out, p::Any) + end + return out +end +function expr_parameters(p::Expr, pos::Int) + if length(p.args) >= pos && + p.args[pos] isa Expr && + p.args[pos].head === :parameters + return p.args[pos] + end + return nothing +end + +"Unwrap (usually block) if it has only one non-linenode child" +function maybe_strip_block(b::Expr) + e1 = findfirst(c -> !isa(c, LineNumberNode), b.args) + isnothing(e1) && return b + e2 = findfirst(c -> !isa(c, LineNumberNode), b.args[e1+1:end]) + !isnothing(e2) && return b + return b.args[e1] +end + +# Get kind by string if exists. TODO relies on internals +function find_kind(s::String) + out = get(JuliaSyntax._kind_str_to_int, s, nothing) + return isnothing(out) ? nothing : JuliaSyntax.Kind(out) +end + +function is_dotted_operator(s::AbstractString) + return length(s) >= 2 && + s[1] === '.' && + JS.is_operator(something(find_kind(s[2:end]), K"None")) +end + +# Expr doesn't record whether or not var"x" was used on x, so just assume one +# was used for any invalid identifier, but lose the information otherwise. +function _insert_var_str(child::NodeId, graph::SyntaxGraph, src::SourceAttrType) + var_id = _insert_tree_node(graph, K"var", src) + setchildren!(graph, var_id, [child]) + setflags!(graph, child, JS.RAW_STRING_FLAG) + setflags!(graph, var_id, JS.NON_TERMINAL_FLAG) + return (var_id, src) +end + +""" +Insert `e` converted to a syntaxtree into graph and recurse on children. Return +a pair (my_node_id, last_srcloc). Should not mutate `e`. + +`src` is the latest location found in the pre-order traversal, and is the line +number node to be associated with `e`. +""" +function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceAttrType) + if e isa Symbol + estr = String(e) + st_k = K"Identifier" + st_id = _insert_tree_node(graph, st_k, src) + setattr!(graph, st_id, name_val=estr) + if !Base.isoperator(e) && !Base.is_valid_identifier(e) + return _insert_var_str(st_id, graph, src) + end + return (st_id, src) + elseif e isa LineNumberNode + return (nothing, e) + elseif e isa QuoteNode + st_id = _insert_tree_node(graph, K"quote", src) + quote_child, _ = _insert_convert_expr(e.value, graph, src) + setchildren!(graph, st_id, NodeId[quote_child]) + return (st_id, src) + elseif e isa String + st_id = _insert_tree_node(graph, K"string", src) + id_inner = _insert_tree_node(graph, K"String", src) + setattr!(graph, id_inner, value=e) + setchildren!(graph, st_id, [id_inner]) + return (st_id, src) + elseif !(e isa Expr) + if !(e isa Union{Number, Bool, Char, GlobalRef, Nothing}) + @info "what is this" e typeof(e) + end + # TODO: st_k of Float. others? + st_k = e isa Integer ? K"Integer" : find_kind(string(typeof(e))) + st_id = _insert_tree_node(graph, isnothing(st_k) ? K"Value" : st_k, src) + setattr!(graph, st_id, value=e) + return (st_id, src) + end + nargs = length(e.args) + + # `e` is an expr. In many cases, it suffices to + # - guess that the kind name is the same as the expr head + # - add no syntax flags + # - map e.args to syntax tree children one-to-one + maybe_kind = find_kind(string(e.head)) + st_k = isnothing(maybe_kind) ? K"None" : maybe_kind + st_flags = 0x0000 + child_exprs = copy(e.args) + + # The following are special cases where the kind, flags, or children are + # different from what we guessed above. + if Base.isoperator(e.head) && st_k === K"None" + # e.head is an updating assignment operator (+=, .-=, etc). Non-= + # dotted ops are wrapped in a call, so we don't reach this. + s = string(e.head) + @assert s[end] === '=' && nargs === 2 + if s[1] === '.' + st_k = K".op=" + op = s[2:end-1] + else + st_k = K"op=" + op = s[1:end-1] + end + child_exprs = [e.args[1], Symbol(op), e.args[2]] + elseif e.head === :comparison + for i = 2:2:length(child_exprs) + op = child_exprs[i] + @assert op isa Symbol + op_s = string(op) + if is_dotted_operator(op_s) + child_exprs[i] = Expr(:., Symbol(op_s[2:end])) + end + end + elseif e.head === :macrocall + @assert nargs >= 1 + a1 = e.args[1] + child_exprs = collect_expr_parameters(e, 2) + if a1 isa Symbol + child_exprs[1] = Expr(:MacroName, a1) + elseif a1 isa Expr && a1.head === :(.) && a1.args[2] isa QuoteNode + child_exprs[1] = Expr(:(.), a1.args[1], Expr(:MacroName, a1.args[2].value)) + elseif a1 isa GlobalRef + # syntax-introduced macrocalls + if a1.name === Symbol("@cmd") + # expr_children = [] + elseif a1.name === Symbol("@doc") + elseif a1.name === Symbol("@int128_str") + elseif a1.name === Symbol("@int128_str") + elseif a1.name === Symbol("@big_str") + end + else + dump(e) + error("Unknown macrocall form $e") + end + + # TODO node->expr handles do blocks here? + elseif e.head === Symbol("'") + @assert nargs === 1 + st_k = K"call" + st_flags |= JS.POSTFIX_OP_FLAG + child_exprs = [e.head, e.args[1]] + elseif e.head === :. && nargs === 2 + a2 = e.args[2] + if a2 isa Expr && a2.head === :tuple + st_k = K"dotcall" + tuple_exprs = collect_expr_parameters(a2, 1) + child_exprs = pushfirst!(tuple_exprs, e.args[1]) + elseif a2 isa QuoteNode && a2.value isa Symbol + e.args[2] = a2.value + elseif a2 isa Expr && a2.head === :MacroName + else + @error "Unknown 2-arg dot form?" e + end + elseif e.head === :for + @assert nargs === 2 + child_exprs = [_to_iterspec([e.args[1]]), e.args[2]] + elseif e.head === :where + @assert nargs >= 2 + if !(e.args[2] isa Expr && e.args[2].head === :braces) + child_exprs = [e.args[1], Expr(:braces, e.args[2:end]...)] + end + elseif e.head in (:tuple, :vect, :braces) + child_exprs = collect_expr_parameters(e, 1) + elseif e.head in (:curly, :ref) + child_exprs = collect_expr_parameters(e, 2) + elseif e.head === :try + child_exprs = Any[e.args[1]] + # Expr: + # (try (block ...) var (block ...) [block ...] [block ...]) + # # try catch_var catch finally else + # SyntaxTree: + # (try (block ...) + # [catch var (block ...)] + # [else (block ...)] + # [finally (block ...)]) + if e.args[2] != false || e.args[3] != false + push!(child_exprs, + Expr(:catch, + e.args[2] === false ? Expr(:catch_var_placeholder) : e.args[2], + e.args[3] === false ? nothing : e.args[3])) + end + if nargs >= 5 + push!(child_exprs, Expr(:else, e.args[5])) + end + if nargs >= 4 + push!(child_exprs, + Expr(:finally, e.args[4] === false ? nothing : e.args[4])) + end + elseif e.head === :generator # TODO flatten + child_exprs = [e.args[1], _to_iterspec(e.args[2:end])] + elseif e.head === :ncat || e.head === :nrow + st_flags |= JS.set_numeric_flags(e.args[1]) + child_exprs = child_exprs[2:end] + elseif e.head === :typed_ncat + st_flags |= JS.set_numeric_flags(e.args[2]) + deleteat!(child_exprs, 2) + elseif e.head === :(->) + @assert nargs === 2 + if e.args[1] isa Symbol + child_exprs[1] = Expr(:tuple, e.args[1]) + end + child_exprs[2] = maybe_strip_block(e.args[2]) + elseif e.head === :call + child_exprs = collect_expr_parameters(e, 2) + a1 = child_exprs[1] + if a1 isa Symbol + a1s = string(a1) + if is_dotted_operator(a1s) + # non-assigning dotop like .+ or .== + st_k = K"dotcall" + child_exprs[1] = Symbol(a1s[2:end]) + end + end + elseif e.head === :(=) + if e.args[1] isa Expr && e.args[1].head === :call + st_k = K"function" + st_flags |= JuliaSyntax.SHORT_FORM_FUNCTION_FLAG + child_exprs[2] = maybe_strip_block(child_exprs[2]) + end + elseif e.head === :module + @assert nargs === 3 + if !e.args[1] + st_flags |= JS.BARE_MODULE_FLAG + end + child_exprs = [e.args[2], e.args[3]] + elseif e.head === :do + # Expr: + # (do (call f args...) (-> (tuple lam_args...) (block ...))) + # SyntaxTree: + # (call f args... (do (tuple lam_args...) (block ...))) + st_k = K"call" + child_exprs = [e.args[1].args..., Expr(:do_lambda, e.args[2].args...)] + elseif e.head === :let + if nargs >= 1 && e.args[1] isa Expr && e.args[1].head !== :block + child_exprs[1] = Expr(:block, e.args[1]) + end + elseif e.head === :struct + e.args[1] && (st_flags |= JS.MUTABLE_FLAG) + child_exprs = child_exprs[2:end] + # TODO handle docstrings after refactor + elseif (e.head === :using || e.head === :import) + _expr_replace!(e, + (e)->(e isa Expr && e.head === :.), + (e)->(e.head = :importpath)) + elseif e.head === :kw + st_k = K"=" + end + + # Temporary heads introduced by converting the parent expr + if e.head === :MacroName + @assert nargs === 1 + st_id = _insert_tree_node(graph, K"MacroName", src, st_flags) + mac_name = string(e.args[1]) + setattr!(graph, st_id, name_val=mac_name == "@__dot__" ? "@." : mac_name) + @info mac_name[2:end] Base.is_valid_identifier(mac_name[2:end]) + if !Base.is_valid_identifier(mac_name[2:end]) + return _insert_var_str(st_id, graph, src) + end + return (st_id, src) + elseif e.head === :catch_var_placeholder + st_id = _insert_tree_node(graph, K"Placeholder", src, st_flags) + setattr!(graph, st_id, name_val="") + return (st_id, src) + elseif e.head === :do_lambda + st_k = K"do" + end + + if st_k === K"None" + dump(e) + error("no kind for $(e.head)") + end + + st_flags |= JS.NON_TERMINAL_FLAG + st_id = _insert_tree_node(graph, st_k, src, st_flags) + st_child_ids = NodeId[] + last_src = src + for c in child_exprs + (c_id, c_src) = _insert_convert_expr(c, graph, last_src) + isnothing(c_id) || push!(st_child_ids, c_id) + last_src = something(c_src, src) + end + + setchildren!(graph, st_id, st_child_ids) + return (st_id, last_src) +end diff --git a/src/desugaring.jl b/src/desugaring.jl index 80f93d06..0729032b 100644 --- a/src/desugaring.jl +++ b/src/desugaring.jl @@ -690,10 +690,10 @@ function expand_dotcall(ctx, ex) ] elseif k == K"comparison" expand_dotcall(ctx, expand_compare_chain(ctx, ex)) - elseif (k == K"&&" || k == K"||") && is_dotted(ex) + elseif k == K".&&" || k == K".||" @ast ctx ex [K"call" "broadcasted"::K"top" - (k == K"&&" ? "andand" : "oror")::K"top" + (k == K".&&" ? "andand" : "oror")::K"top" (expand_dotcall(ctx, arg) for arg in children(ex))... ] else @@ -702,8 +702,7 @@ function expand_dotcall(ctx, ex) end function expand_fuse_broadcast(ctx, ex) - if kind(ex) == K"=" - @assert is_dotted(ex) + if kind(ex) == K".=" || kind(ex) == K".op=" @chk numchildren(ex) == 2 lhs = ex[1] kl = kind(lhs) @@ -1316,7 +1315,7 @@ end function expand_update_operator(ctx, ex) k = kind(ex) - dotted = is_dotted(ex) + dotted = k == K".op=" @chk numchildren(ex) == 3 lhs = ex[1] @@ -1358,7 +1357,7 @@ function expand_update_operator(ctx, ex) @ast ctx ex [K"block" stmts... - [K"="(syntax_flags=(dotted ? JuliaSyntax.DOTOP_FLAG : nothing)) + [(dotted ? K".=" : K"=") lhs [(dotted ? K"dotcall" : K"call") op @@ -4254,7 +4253,7 @@ function expand_forms_2(ctx::DesugaringContext, ex::SyntaxTree, docs=nothing) throw(LoweringError(ex, "unimplemented or unsupported atomic declaration")) elseif k == K"call" expand_call(ctx, ex) - elseif k == K"dotcall" || ((k == K"&&" || k == K"||") && is_dotted(ex)) + elseif k == K"dotcall" || k == K".&&" || k == K".||" || k == K".=" expand_forms_2(ctx, expand_fuse_broadcast(ctx, ex)) elseif k == K"." expand_forms_2(ctx, expand_dot(ctx, ex)) @@ -4290,14 +4289,10 @@ function expand_forms_2(ctx::DesugaringContext, ex::SyntaxTree, docs=nothing) adopt_scope(string(k)::K"Identifier", ex) children(ex)... ]) - elseif k == K"op=" + elseif k == K"op=" || k == K".op=" expand_forms_2(ctx, expand_update_operator(ctx, ex)) elseif k == K"=" - if is_dotted(ex) - expand_forms_2(ctx, expand_fuse_broadcast(ctx, ex)) - else - expand_assignment(ctx, ex) - end + expand_assignment(ctx, ex) elseif k == K"break" numchildren(ex) > 0 ? ex : @ast ctx ex [K"break" "loop_exit"::K"symbolic_label"] diff --git a/src/syntax_graph.jl b/src/syntax_graph.jl index 28af9cfb..0a08d598 100644 --- a/src/syntax_graph.jl +++ b/src/syntax_graph.jl @@ -137,17 +137,20 @@ function Base.getproperty(graph::SyntaxGraph, name::Symbol) end function sethead!(graph, id::NodeId, h::JuliaSyntax.SyntaxHead) - graph.kind[id] = kind(h) - f = flags(h) - if f != 0 - graph.syntax_flags[id] = f - end + sethead!(graph, id, kind(h)) + setflags!(graph, id, flags(h)) end function sethead!(graph, id::NodeId, k::Kind) graph.kind[id] = k end +function setflags!(graph, id::NodeId, f::UInt16) + if f != 0 + graph.syntax_flags[id] = f + end +end + function _convert_nodes(graph::SyntaxGraph, node::SyntaxNode) id = newnode!(graph) sethead!(graph, id, head(node)) @@ -307,6 +310,7 @@ JuliaSyntax.source_line(src::LineNumberNode) = src.line # The follow somewhat strange cases are for where LineNumberNode is standing in # for SourceFile because we've only got Expr-based provenance info JuliaSyntax.sourcefile(src::LineNumberNode) = src +JuliaSyntax.sourcetext(src::LineNumberNode) = SubString("") JuliaSyntax.source_location(src::LineNumberNode, byte_index::Integer) = (src.line, 0) JuliaSyntax.source_location(::Type{LineNumberNode}, src::LineNumberNode, byte_index::Integer) = src JuliaSyntax.filename(src::LineNumberNode) = string(src.file) @@ -537,13 +541,11 @@ end JuliaSyntax.sourcefile(ex::SyntaxTree) = sourcefile(sourceref(ex)) JuliaSyntax.byte_range(ex::SyntaxTree) = byte_range(sourceref(ex)) -function JuliaSyntax._expr_leaf_val(ex::SyntaxTree) +function JuliaSyntax._expr_leaf_val(ex::SyntaxTree, _...) name = get(ex, :name_val, nothing) - if !isnothing(name) - Symbol(name) - else - ex.value - end + !isnothing(name) && return Symbol(name) + name = get(ex, :value, nothing) + return name end Base.Expr(ex::SyntaxTree) = JuliaSyntax.to_expr(ex) @@ -604,7 +606,7 @@ macro SyntaxTree(ex_old) throw(ArgumentError("@SyntaxTree expects a `quote` block or `:`-quoted expression")) end # 2. Re-parse the current source file as SyntaxTree instead - fname = String(__source__.file) + fname = isnothing(__source__.file) ? error("No current file") : String(__source__.file) if occursin(r"REPL\[\d+\]", fname) # Assume we should look at last history entry in REPL try diff --git a/test/compat.jl b/test/compat.jl new file mode 100644 index 00000000..c43985ab --- /dev/null +++ b/test/compat.jl @@ -0,0 +1,373 @@ +using Test +using JuliaLowering +const JS = JuliaSyntax +const JL = JuliaLowering + +# Parse string->expr->tree->expr. This is for bulk testing that the expr->tree +# conversion preserves semantics. +function parse_ete(args...) + outex, pos = JS.core_parser_hook(args...) + st = JL.expr_to_syntaxtree(outex) + local out + try + out = Expr(st) + catch e + show(args[1]) + @error "Failed to convert back to expr:" st + Base.showerror(stdout, e, Base.catch_backtrace()) + return outex, pos + end + return out, pos + # @warn "after:" st +end + +function fix_module(m::Module) + # Make `m` equivalent to `module anonymous end` + Core.eval(m, :(eval(x) = Core.eval($m, x))) + Core.eval(m, :(include(x) = Base.include($m, x))) + m +end + +test_mod_1 = fix_module(Module()) +test_mod_2 = fix_module(Module()) + +# parse and eval "normally" vs. with expr->tree->expr transformation, returning +# the result of both evaluations. +function test_eval_ete(s::AbstractString) + ps = JS.ParseStream(s) + JS.parse!(ps) + good_tree = JS.build_tree(JL.SyntaxTree, ps) + local good_expr + try + good_expr = Expr(good_tree) + try + good_out = Core.eval(test_mod_1, good_expr) + Core._setparser!(parse_ete) + test_out = Core.eval(test_mod_2, Meta.parseall(s)) + # @warn "reference tree:" + # show(stdout, MIME("text/plain"), good_tree) + @test good_out == test_out + catch e + show(stdout, MIME("text/plain"), good_expr) + Base.showerror(stdout, e, Base.catch_backtrace()) + @test "test threw; see output" == "" + finally + Core._setparser!(JS.core_parser_hook) + # Core.eval(test_mod_2, good_expr) # even them out? + end + + catch e_ + @error good_tree + Base.showerror(stdout, e_, Base.catch_backtrace()) + @test "failed to convert known-good syntax tree???" == "" + end +end + +# Remove any information that can't be recovered from an Expr +function normalize_st!(st) + k = JS.kind(st) + + if JS.is_infix_op_call(st) && (k === K"call" || k === K"dotcall") + # Infix calls are not preserved in Expr + args = JS.children(st) + + pre_st_args = JL.NodeId[args[2]._id, args[1]._id] + for c in args[3:end] + # there has got to be a better way + push!(pre_st_args, c._id) + end + pre_st_flags = (JS.flags(st) & ~JS.INFIX_FLAG) | JS.PREFIX_CALL_FLAG + pre_st = JL.makeleaf(st._graph, st, k) + JL.setchildren!(pre_st._graph, pre_st._id, pre_st_args) + JL.setflags!(pre_st._graph, pre_st._id, pre_st_flags) + return pre_st + elseif k in JS.KSet"tuple block macrocall" + # Parens are not preserved + JL.setflags!(st._graph, st._id, JS.flags(st) & ~JS.PARENS_FLAG) + elseif k === K"toplevel" + JL.setflags!(st._graph, st._id, JS.flags(st) & ~JS.TOPLEVEL_SEMICOLONS_FLAG) + end + + # All ops are prefix ops in an expr + JL.setflags!(st._graph, st._id, JS.flags(st) & ~JS.PREFIX_OP_FLAG) + + return st +end + +function st_roughly_equal(st_good, st_test) + st_good = normalize_st!(st_good) + out = kind(st_good) === kind(st_test) && + JS.flags(st_good) === JS.flags(st_test) && + JS.numchildren(st_good) === JS.numchildren(st_test) && + JS.is_leaf(st_good) === JS.is_leaf(st_test) && + get(st_good, :value, nothing) === get(st_test, :value, nothing) && + get(st_good, :name_val, nothing) === get(st_test, :name_val, nothing) && + all(map(st_roughly_equal, JS.children(st_good), JS.children(st_test))) + !out && @warn("!st_roughly_equal (normalized_reference, test):", + JS.sourcetext(st_good), st_good, st_test) + return out +end +# @test tree ~= tree->expr->tree +function tet_eq(s::String) + p1 = JS.parsestmt(SyntaxTree, s; ignore_errors=true) + p2 = JL.expr_to_syntaxtree(Expr(p1)) + @test st_roughly_equal(p1, p2) +end + +@testset "expr->syntaxtree" begin + @testset "semantics only" begin + test_eval_ete("let x = 2; x += 5; x -= 1; [1] .*= 1; end") + test_eval_ete("try; 1; catch e; e; else; 2; finally; 3; end") + test_eval_ete("for x in 1:2, y in 3:4; x + y; end") + + test_eval_ete("[x+y for x in 1:2, y in 3:4]") + test_eval_ete("Int[x+y for x in 1:2, y in 3:4 if true]") + + test_eval_ete("for x in 1; x+=1\n if true\n continue \n elseif false \n break\n end\n end") + test_eval_ete("@time 1") + test_eval_ete("Base.Meta.@lower 1") + test_eval_ete("function foo(x, y=1; z, what::Int=5); x + y + z + what; end; foo(1,2;z=3)") + + test_eval_ete("(()->1)()") + test_eval_ete("((x)->2)(3)") + test_eval_ete("((x,y)->4)(5,6)") + test_eval_ete("filter([1,2,3]) do x; x > 1; end") + test_eval_ete(""" + struct X + f1::Int # hi + "foo" + f2::Int + f3::Int + X(y) = new(y,y,y) + end + """) + test_eval_ete("global x,y") + test_eval_ete("global (x,y)") + test_eval_ete("999999999999999999999999999999999999999") + end + + @testset "syntaxtree equivalence (tests from JuliaSyntax expr.jl)" begin + tet_eq("begin a\nb\n\nc\nend") + tet_eq("(a;b;c)") + tet_eq("begin end") + tet_eq("(;;)") + tet_eq("a;b") + tet_eq("module A\n\nbody\nend") + tet_eq("function f()\na\n\nb\nend") + tet_eq("f() = 1") + tet_eq("macro f()\na\nend") + tet_eq("function f end") + tet_eq("macro f end") + tet_eq("function (f() where T) end") + tet_eq("function (f()::S) end") + tet_eq("a -> b") + tet_eq("(a,) -> b") + tet_eq("(a where T) -> b") + tet_eq("a -> (\nb;c)") + tet_eq("a -> begin\nb\nc\nend") + tet_eq("(a;b=1) -> c") + tet_eq("(a...;b...) -> c") + tet_eq("(;) -> c") + tet_eq("a::T -> b") + tet_eq("if a\nb\nelseif c\n d\nend") + tet_eq("let i=is, j=js\nbody\nend") + tet_eq("for x=xs\n\nend") + tet_eq("for x=xs\ny\nend") + tet_eq("while cond\n\nend") + tet_eq("while cond\ny\nend") + tet_eq("f() = xs") + tet_eq("f() =\n(a;b)") + tet_eq("f() =\nbegin\na\nb\nend") + tet_eq("let f(x) =\ng(x)=1\nend") + tet_eq("f() .= xs") + tet_eq("for i=is body end") + tet_eq("for i=is, j=js\nbody\nend") + tet_eq("function (xs...)\nbody end") + tet_eq("\"str\"") + tet_eq("\"\$(\"str\")\"") + tet_eq("```\n a\n b```") + tet_eq("\"\"\"\n a\n \$x\n b\n c\"\"\"") + tet_eq("`x") + tet_eq("`") + tet_eq("'a'") + tet_eq("'α'") + tet_eq("'\\xce\\xb1'") + tet_eq("f(x) do y\n body end") + tet_eq("@f(x) do y body end") + tet_eq("f(x; a=1) do y body end") + tet_eq("g(f(x) do y\n body end)") + tet_eq("f(a=1)") + tet_eq("f(; b=2)") + tet_eq("f(a=1; b=2)") + tet_eq("f(a; b; c)") + tet_eq("+(a=1,)") + tet_eq("(a=1)()") + tet_eq("(x=1) != 2") + tet_eq("+(a=1)") + tet_eq("(a=1)'") + tet_eq("(a=1)'ᵀ") + tet_eq("f.(a=1; b=2)") + tet_eq("(a=1,)") + tet_eq("(a=1,; b=2)") + tet_eq("(a=1,; b=2; c=3)") + tet_eq("x[i=j]") + tet_eq("(i=j)[x]") + tet_eq("x[a, b; i=j]") + tet_eq("(i=j){x}") + tet_eq("x{a, b; i=j}") + tet_eq("[a=1,; b=2]") + tet_eq("{a=1,; b=2}") + tet_eq("f(a .= 1)") + tet_eq("f(((a = 1)))") + tet_eq("(((a = 1)),)") + tet_eq("(;((a = 1)),)") + tet_eq("a.b") + tet_eq("a.\$b") + tet_eq("a.:b") + tet_eq("a.@b x") + tet_eq("f.(x,y)") + tet_eq("f.(x=1)") + tet_eq("f.(a=1; b=2)") + tet_eq("(a=1).()") + tet_eq("x .+ y") + tet_eq("(x=1) .+ y") + tet_eq("a .< b .< c") + tet_eq("a .< (.<) .< c") + tet_eq(".*(x)") + tet_eq(".+(x)") + tet_eq(".+x") + tet_eq("(.+)(x)") + tet_eq("(.+).(x)") + tet_eq(".+") + tet_eq(":.+") + tet_eq(":(.+)") + tet_eq("quote .+ end") + tet_eq(".+{x}") + tet_eq(":.=") + tet_eq(":(.=)") + tet_eq("f(.+)") + tet_eq("(a, .+)") + tet_eq("A.:.+") + tet_eq("./x") + tet_eq("x += y") + tet_eq("x .+= y") + tet_eq(":+=") + tet_eq(":(+=)") + tet_eq(":.+=") + tet_eq(":(.+=)") + tet_eq("x \u2212= y") + tet_eq("let x=1\n end") + tet_eq("let x=1 ; end") + tet_eq("let x ; end") + tet_eq("let x::1 ; end") + tet_eq("let x=1,y=2 end") + tet_eq("let x+=1 ; end") + tet_eq("let ; end") + tet_eq("let ; body end") + tet_eq("let\na\nb\nend") + tet_eq("A where T") + tet_eq("A where {T}") + tet_eq("A where {S, T}") + tet_eq("A where {X, Y; Z}") + tet_eq("@m\n") + tet_eq("\n@m") + tet_eq("@m(x; a)") + tet_eq("@m(a=1; b=2)") + tet_eq("@.") + tet_eq("using A: @.") + tet_eq("@var\"#\" a") + tet_eq("A.@var\"#\" a") + tet_eq("@S[a,b]") + tet_eq("@S[a b]") + tet_eq("@S[a; b]") + tet_eq("@S[a ;; b]") + tet_eq("var\"x\"") + tet_eq("var\"\"") + tet_eq("var\"\\\"\"") + tet_eq("var\"\\\\\\\"\"") + tet_eq("var\"\\\\x\"") + tet_eq("var\"x\"+y") + tet_eq("[x,y ; z]") + tet_eq("[a ;;; b ;;;; c]") + tet_eq("[a b ; c d]") + tet_eq("[a\nb]") + tet_eq("[a b]") + tet_eq("[a b ; c d]") + tet_eq("T[a ;;; b ;;;; c]") + tet_eq("T[a b ; c d]") + tet_eq("T[a\nb]") + tet_eq("T[a b]") + tet_eq("T[a b ; c d]") + tet_eq("(x for a in as for b in bs)") + tet_eq("(x for a in as, b in bs)") + tet_eq("(x for a in as, b in bs if z)") + tet_eq("(x for a in as, b in bs for c in cs, d in ds)") + tet_eq("(x for a in as for b in bs if z)") + tet_eq("(x for a in as if z for b in bs)") + tet_eq("[x for a = as for b = bs if cond1 for c = cs if cond2]" ) + tet_eq("[x for a = as if begin cond2 end]" ) + tet_eq("(x for a in as if z)") + tet_eq("try x catch e; y end") + tet_eq("try x finally y end") + tet_eq("try x catch e; y finally z end") + tet_eq("try x catch e; y else z end") + tet_eq("try x catch e; y else z finally w end") + tet_eq("try x finally y catch e z end") + tet_eq("try x end") + tet_eq("2x") + tet_eq("(2)(3)x") + tet_eq("\"x\" f") + tet_eq("\n\"x\" f") + tet_eq("foo\"str\"") + tet_eq("\n`str`") + tet_eq("foo`str`") + tet_eq("foo`str`flag") + tet_eq("foo```\n a\n b```") + tet_eq("@foo_cmd `str`") + tet_eq("return x") + tet_eq("return") + tet_eq("0x00000000000000001") + tet_eq("(0x00000000000000001)") + tet_eq("struct A end") + tet_eq("mutable struct A end") + tet_eq("struct A <: B \n a::X \n end") + tet_eq("struct A \n a \n b \n end") + tet_eq("struct A const a end") + tet_eq("struct A \n \"doc\" \n a end") + tet_eq("export a") + tet_eq("export @a") + tet_eq("export @var\"'\"") + tet_eq("export a, \n @b") + tet_eq("export +, ==") + tet_eq("export \n a") + tet_eq("global x") + tet_eq("local x") + tet_eq("global x,y") + tet_eq("global const x = 1") + tet_eq("local const x = 1") + tet_eq("const global x = 1") + tet_eq("const local x = 1") + tet_eq("const x,y = 1,2") + tet_eq("const x = 1") + tet_eq("global x ~ 1") + tet_eq("global x += 1") + tet_eq("global (x,y)") + tet_eq("local (x,y)") + tet_eq("(;)") + tet_eq("(; a=1)") + tet_eq("(; a=1; b=2)") + tet_eq("(a; b; c,d)") + tet_eq("module A end") + tet_eq("baremodule A end") + tet_eq("--") + tet_eq("(x") + tet_eq("x do") + tet_eq("x var\"y\"") + tet_eq("var\"y") + tet_eq("import A") + tet_eq("import A.(:b).:c: x.:z") + tet_eq("import A.:+") + tet_eq("import A.(:+)") + tet_eq("import A.:(+)") + end +end diff --git a/test/functions_ir.jl b/test/functions_ir.jl index 5f701b39..6152a9d0 100644 --- a/test/functions_ir.jl +++ b/test/functions_ir.jl @@ -1474,7 +1474,7 @@ end 19 (call core.svec %₁₆ %₁₇ %₁₈) 20 --- method core.nothing %₁₉ slots: [slot₁/#self#(!read) slot₂/x(!read) slot₃/y(!read)] - 1 (meta :generated (new JuliaLowering.GeneratedFunctionStub TestMod.#f_only_generated@generator#0 SourceRef(SourceFile("@generated function f_only_generated(x, y)\n generator_code(x,y)\nend", 0, nothing, 1, [1, 44, 68, 71]), 1, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"macrocall", 0x0000), 0x00000046, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"@", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"MacroName", 0x0000), 0x00000009, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"function", 0x0000), 0x0000003b, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"function", 0x0001), 0x00000008, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0000), 0x00000016, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000010, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0000), 0x00000019, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0000), 0x00000013, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000e, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"end", 0x0001), 0x00000003, nothing)])])) (call core.svec :#self# :x :y) (call core.svec))) + 1 (meta :generated (new JuliaLowering.GeneratedFunctionStub TestMod.#f_only_generated@generator#0 SourceRef(SourceFile("@generated function f_only_generated(x, y)\n generator_code(x,y)\nend", 0, nothing, 1, [1, 44, 68]), 1, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"macrocall", 0x0080), 0x00000046, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"@", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"MacroName", 0x0000), 0x00000009, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"function", 0x0080), 0x0000003b, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"function", 0x0001), 0x00000008, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0080), 0x00000016, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000010, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0080), 0x00000019, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0080), 0x00000013, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000e, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"end", 0x0001), 0x00000003, nothing)])])) (call core.svec :#self# :x :y) (call core.svec))) 2 (meta :generated_only) 3 (return core.nothing) 21 (latestworld) @@ -1521,7 +1521,7 @@ end 19 (call core.svec %₁₆ %₁₇ %₁₈) 20 --- method core.nothing %₁₉ slots: [slot₁/#self#(!read) slot₂/x slot₃/y slot₄/maybe_gen_stuff slot₅/nongen_stuff] - 1 (meta :generated (new JuliaLowering.GeneratedFunctionStub TestMod.#f_partially_generated@generator#0 SourceRef(SourceFile("function f_partially_generated(x, y)\n nongen_stuff = bothgen(x, y)\n if @generated\n quote\n maybe_gen_stuff = some_gen_stuff(x, y)\n end\n else\n maybe_gen_stuff = some_nongen_stuff(x, y)\n end\n (nongen_stuff, maybe_gen_stuff)\nend", 0, nothing, 1, [1, 38, 71, 89, 103, 154, 166, 175, 225, 233, 269, 272]), 1, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"function", 0x0000), 0x0000010f, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"function", 0x0001), 0x00000008, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0000), 0x0000001b, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000015, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0000), 0x000000e8, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0000), 0x0000001c, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000c, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0000), 0x0000000d, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000007, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)])]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"if", 0x0000), 0x0000009d, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"if", 0x0001), 0x00000002, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"macrocall", 0x0000), 0x0000000a, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"@", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"MacroName", 0x0000), 0x00000009, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0000), 0x00000052, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000009, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"quote", 0x0000), 0x00000044, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0000), 0x00000044, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"quote", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x0000000d, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0000), 0x00000026, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000f, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0000), 0x00000014, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000e, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)])]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000009, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"end", 0x0001), 0x00000003, nothing)])]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"else", 0x0001), 0x00000004, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0000), 0x00000037, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000009, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0000), 0x00000029, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000f, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0000), 0x00000017, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000011, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)])]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"end", 0x0001), 0x00000003, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"tuple", 0x0020), 0x0000001f, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000c, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000f, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"end", 0x0001), 0x00000003, nothing)])) (call core.svec :#self# :x :y) (call core.svec))) + 1 (meta :generated (new JuliaLowering.GeneratedFunctionStub TestMod.#f_partially_generated@generator#0 SourceRef(SourceFile("function f_partially_generated(x, y)\n nongen_stuff = bothgen(x, y)\n if @generated\n quote\n maybe_gen_stuff = some_gen_stuff(x, y)\n end\n else\n maybe_gen_stuff = some_nongen_stuff(x, y)\n end\n (nongen_stuff, maybe_gen_stuff)\nend", 0, nothing, 1, [1, 38, 71, 89, 103, 154, 166, 175, 225, 233, 269]), 1, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"function", 0x0080), 0x0000010f, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"function", 0x0001), 0x00000008, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0080), 0x0000001b, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000015, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0080), 0x000000e8, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0080), 0x0000001c, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000c, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0080), 0x0000000d, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000007, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)])]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"if", 0x0080), 0x0000009d, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"if", 0x0001), 0x00000002, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"macrocall", 0x0080), 0x0000000a, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"@", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"MacroName", 0x0000), 0x00000009, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0080), 0x00000052, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000009, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"quote", 0x0080), 0x00000044, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0080), 0x00000044, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"quote", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x0000000d, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0080), 0x00000026, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000f, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0080), 0x00000014, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000e, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)])]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000009, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"end", 0x0001), 0x00000003, nothing)])]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"else", 0x0001), 0x00000004, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"block", 0x0080), 0x00000037, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000009, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0080), 0x00000029, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000f, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"=", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"call", 0x0080), 0x00000017, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000011, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)])]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"end", 0x0001), 0x00000003, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000005, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"tuple", 0x00a0), 0x0000001f, JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}[JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"(", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000c, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K",", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Whitespace", 0x0001), 0x00000001, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"Identifier", 0x0000), 0x0000000f, nothing), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K")", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"NewlineWs", 0x0001), 0x00000001, nothing)]), JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}(JuliaSyntax.SyntaxHead(K"end", 0x0001), 0x00000003, nothing)])) (call core.svec :#self# :x :y) (call core.svec))) 2 TestMod.bothgen 3 (= slot₅/nongen_stuff (call %₂ slot₂/x slot₃/y)) 4 TestMod.some_nongen_stuff From 5c6df5a12cd367eb842f1e4be764e8fffbc2d1a0 Mon Sep 17 00:00:00 2001 From: Em Chu <61633163+mlechu@users.noreply.github.com> Date: Wed, 2 Jul 2025 17:04:11 -0700 Subject: [PATCH 22/35] Apply suggestions from code review Thanks! Co-authored-by: Cody Tapscott <84105208+topolarity@users.noreply.github.com> --- src/compat.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compat.jl b/src/compat.jl index cc56acaa..75540ee5 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -83,13 +83,13 @@ function collect_expr_parameters(e::Expr, pos::Int) params = expr_parameters(e, pos) isnothing(params) && return e.args args = Any[e.args[1:pos-1]..., e.args[pos+1:end]...] - return _flatten_params(params, args) + return _flatten_params!(args, params) end -function _flatten_params(p::Expr, out::Vector{Any}) +function _flatten_params!(out::Vector{Any}, p::Expr) p1 = expr_parameters(p, 1) if !isnothing(p1) push!(out, Expr(:parameters, p.args[2:end]...)) - _flatten_params(p1, out) + _flatten_params!(out, p1) else push!(out, p::Any) end @@ -252,7 +252,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA end elseif e.head === :for @assert nargs === 2 - child_exprs = [_to_iterspec([e.args[1]]), e.args[2]] + child_exprs = Expr[_to_iterspec(Any[e.args[1]]), e.args[2]] elseif e.head === :where @assert nargs >= 2 if !(e.args[2] isa Expr && e.args[2].head === :braces) From 01e33d4bed0c8dbec92958615b0ef5be00e56e4d Mon Sep 17 00:00:00 2001 From: Em Chu Date: Thu, 3 Jul 2025 09:41:47 -0700 Subject: [PATCH 23/35] Consistency, comments --- src/compat.jl | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/compat.jl b/src/compat.jl index 75540ee5..c6e0dbb6 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -1,6 +1,6 @@ const JS = JuliaSyntax -function _insert_tree_node(graph::SyntaxGraph, k::JuliaSyntax.Kind, +function _insert_tree_node(graph::SyntaxGraph, k::JS.Kind, src::SourceAttrType, flags::UInt16=0x0000) id = newnode!(graph) sethead!(graph, id, k) @@ -29,7 +29,7 @@ function expr_to_syntaxtree(@nospecialize(e), lnn::Union{LineNumberNode, Nothing # Provenance sinkhole for all nodes until we hit a linenode dummy_src = SourceRef( SourceFile("No source for expression $e"), - 1, JuliaSyntax.GreenNode(K"None", 0)) + 1, JS.GreenNode(K"None", 0)) _insert_tree_node(graph, K"None", dummy_src) else lnn @@ -115,8 +115,8 @@ end # Get kind by string if exists. TODO relies on internals function find_kind(s::String) - out = get(JuliaSyntax._kind_str_to_int, s, nothing) - return isnothing(out) ? nothing : JuliaSyntax.Kind(out) + out = get(JS._kind_str_to_int, s, nothing) + return isnothing(out) ? nothing : JS.Kind(out) end function is_dotted_operator(s::AbstractString) @@ -167,7 +167,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA return (st_id, src) elseif !(e isa Expr) if !(e isa Union{Number, Bool, Char, GlobalRef, Nothing}) - @info "what is this" e typeof(e) + @info "unknown leaf type in expr, guessing value:" e typeof(e) end # TODO: st_k of Float. others? st_k = e isa Integer ? K"Integer" : find_kind(string(typeof(e))) @@ -219,7 +219,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA elseif a1 isa Expr && a1.head === :(.) && a1.args[2] isa QuoteNode child_exprs[1] = Expr(:(.), a1.args[1], Expr(:MacroName, a1.args[2].value)) elseif a1 isa GlobalRef - # syntax-introduced macrocalls + # TODO syntax-introduced macrocalls if a1.name === Symbol("@cmd") # expr_children = [] elseif a1.name === Symbol("@doc") @@ -313,7 +313,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA elseif e.head === :(=) if e.args[1] isa Expr && e.args[1].head === :call st_k = K"function" - st_flags |= JuliaSyntax.SHORT_FORM_FUNCTION_FLAG + st_flags |= JS.SHORT_FORM_FUNCTION_FLAG child_exprs[2] = maybe_strip_block(child_exprs[2]) end elseif e.head === :module @@ -351,7 +351,6 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA st_id = _insert_tree_node(graph, K"MacroName", src, st_flags) mac_name = string(e.args[1]) setattr!(graph, st_id, name_val=mac_name == "@__dot__" ? "@." : mac_name) - @info mac_name[2:end] Base.is_valid_identifier(mac_name[2:end]) if !Base.is_valid_identifier(mac_name[2:end]) return _insert_var_str(st_id, graph, src) end From ebe29eea0e8e664148cd29f31730d8562c8f43d6 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Thu, 3 Jul 2025 18:14:43 -0700 Subject: [PATCH 24/35] Tweaks for macros --- src/compat.jl | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/compat.jl b/src/compat.jl index c6e0dbb6..5fb0d1f0 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -17,7 +17,7 @@ the last seen LineNumberNode in the pre-order expr traversal). Last-resort option so that, for example, we can lower the output of old Expr-producing macros. Always prefer re-parsing source text over using this. -Does not support lowered exprs. +Supports parsed and/or macro-expanded exprs, but not lowered exprs """ function expr_to_syntaxtree(@nospecialize(e), lnn::Union{LineNumberNode, Nothing}=nothing) graph = SyntaxGraph() @@ -154,11 +154,11 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA return (st_id, src) elseif e isa LineNumberNode return (nothing, e) - elseif e isa QuoteNode - st_id = _insert_tree_node(graph, K"quote", src) - quote_child, _ = _insert_convert_expr(e.value, graph, src) - setchildren!(graph, st_id, NodeId[quote_child]) - return (st_id, src) + # elseif e isa QuoteNode + # st_id = _insert_tree_node(graph, K"quote", src) + # quote_child, _ = _insert_convert_expr(e.value, graph, src) + # setchildren!(graph, st_id, NodeId[quote_child]) + # return (st_id, src) elseif e isa String st_id = _insert_tree_node(graph, K"string", src) id_inner = _insert_tree_node(graph, K"String", src) @@ -211,9 +211,11 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA end end elseif e.head === :macrocall - @assert nargs >= 1 + @assert nargs >= 2 a1 = e.args[1] - child_exprs = collect_expr_parameters(e, 2) + child_exprs = collect_expr_parameters(e, 3) + # macrocall has a linenode "argument" here. should we set src? + deleteat!(child_exprs, 2) if a1 isa Symbol child_exprs[1] = Expr(:MacroName, a1) elseif a1 isa Expr && a1.head === :(.) && a1.args[2] isa QuoteNode @@ -227,12 +229,20 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA elseif a1.name === Symbol("@int128_str") elseif a1.name === Symbol("@big_str") end + elseif a1 isa Function else - dump(e) - error("Unknown macrocall form $e") + error("Unknown macrocall form $(sprint(dump, e))") end # TODO node->expr handles do blocks here? + elseif e.head === :escape || e.head === Symbol("hygienic-scope") + @assert nargs >= 1 + # Existing behaviour appears to just ignore any extra args + return _insert_convert_expr(e.args[1], graph, src) + elseif e.head === :meta + @assert nargs <= 2 + @assert e.args[1] isa Symbol + child_exprs[1] = Expr(:sym_not_identifier, e.args[1]) elseif e.head === Symbol("'") @assert nargs === 1 st_k = K"call" @@ -359,13 +369,18 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA st_id = _insert_tree_node(graph, K"Placeholder", src, st_flags) setattr!(graph, st_id, name_val="") return (st_id, src) + elseif e.head === :sym_not_identifier + estr = String(e.args[1]) + st_k = K"Symbol" + st_id = _insert_tree_node(graph, st_k, src) + setattr!(graph, st_id, name_val=estr) + return (st_id, src) elseif e.head === :do_lambda st_k = K"do" end if st_k === K"None" - dump(e) - error("no kind for $(e.head)") + error("no kind for expr head `$(e.head)`\n$(sprint(dump, e))") end st_flags |= JS.NON_TERMINAL_FLAG From cc8830126fb0f6da922e194beccf06cf7500b836 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Tue, 8 Jul 2025 12:02:40 -0700 Subject: [PATCH 25/35] More tiny fixes --- src/compat.jl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/compat.jl b/src/compat.jl index 5fb0d1f0..7868a343 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -143,11 +143,13 @@ a pair (my_node_id, last_srcloc). Should not mutate `e`. number node to be associated with `e`. """ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceAttrType) - if e isa Symbol - estr = String(e) - st_k = K"Identifier" - st_id = _insert_tree_node(graph, st_k, src) - setattr!(graph, st_id, name_val=estr) + if isnothing(e) + st_id = _insert_tree_node(graph, K"core", src) + setattr!(graph, st_id, name_val="nothing") + return (st_id, src) + elseif e isa Symbol + st_id = _insert_tree_node(graph, K"Identifier", src) + setattr!(graph, st_id, name_val=String(e)) if !Base.isoperator(e) && !Base.is_valid_identifier(e) return _insert_var_str(st_id, graph, src) end @@ -155,7 +157,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA elseif e isa LineNumberNode return (nothing, e) # elseif e isa QuoteNode - # st_id = _insert_tree_node(graph, K"quote", src) + # st_id = _insert_tree_node(graph, K"inert", src) # quote_child, _ = _insert_convert_expr(e.value, graph, src) # setchildren!(graph, st_id, NodeId[quote_child]) # return (st_id, src) @@ -353,6 +355,8 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA (e)->(e.head = :importpath)) elseif e.head === :kw st_k = K"=" + elseif e.head === Symbol("latestworld-if-toplevel") + st_k = K"latestworld_if_toplevel" end # Temporary heads introduced by converting the parent expr From fb2ea800bfbef53faa88c8c9bf142231e53fcda1 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Thu, 10 Jul 2025 09:18:40 -0700 Subject: [PATCH 26/35] Use macro expansion ctx param Doesn't handle hygiene yet, but necessary for it. TODO: We cannot handle intentional un-hygiene from the user with the current data structures, as far as I'm aware. --- src/compat.jl | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/compat.jl b/src/compat.jl index 7868a343..2a5bad65 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -19,12 +19,17 @@ Expr-producing macros. Always prefer re-parsing source text over using this. Supports parsed and/or macro-expanded exprs, but not lowered exprs """ -function expr_to_syntaxtree(@nospecialize(e), lnn::Union{LineNumberNode, Nothing}=nothing) - graph = SyntaxGraph() - ensure_attributes!(graph, - kind=Kind, syntax_flags=UInt16, - source=SourceAttrType, var_id=Int, value=Any, - name_val=String, is_toplevel_thunk=Bool) +function expr_to_syntaxtree(@nospecialize(e), + mctx::Union{MacroExpansionContext, Nothing}=nothing, + lnn::Union{LineNumberNode, Nothing}=nothing) + graph = if isnothing(mctx) + ensure_attributes!(SyntaxGraph(), + kind=Kind, syntax_flags=UInt16, + source=SourceAttrType, var_id=Int, value=Any, + name_val=String, is_toplevel_thunk=Bool) + else + mctx.graph + end toplevel_src = if isnothing(lnn) # Provenance sinkhole for all nodes until we hit a linenode dummy_src = SourceRef( From 23bd0c492231b6a2756f8e30f4e0f5de1ff38d6e Mon Sep 17 00:00:00 2001 From: Em Chu Date: Fri, 11 Jul 2025 10:13:59 -0700 Subject: [PATCH 27/35] Handle Expr-nospecialize --- src/ast.jl | 7 +++++-- src/compat.jl | 29 +++++++++++++++++++++++------ src/syntax_graph.jl | 8 ++++++-- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/ast.jl b/src/ast.jl index 7188eba4..c16a9a51 100644 --- a/src/ast.jl +++ b/src/ast.jl @@ -498,7 +498,7 @@ end # the middle of a pass. const CompileHints = Base.ImmutableDict{Symbol,Any} -function setmeta(ex::SyntaxTree; kws...) +function setmeta!(ex::SyntaxTree; kws...) @assert length(kws) == 1 # todo relax later ? key = first(keys(kws)) value = first(values(kws)) @@ -506,9 +506,12 @@ function setmeta(ex::SyntaxTree; kws...) m = get(ex, :meta, nothing) isnothing(m) ? CompileHints(key, value) : CompileHints(m, key, value) end - setattr(ex; meta=meta) + setattr!(ex; meta=meta) + ex end +setmeta(ex::SyntaxTree; kws...) = setmeta!(copy_node(ex); kws...) + function getmeta(ex::SyntaxTree, name::Symbol, default) meta = get(ex, :meta, nothing) isnothing(meta) ? default : get(meta, name, default) diff --git a/src/compat.jl b/src/compat.jl index 2a5bad65..ff954e5a 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -191,7 +191,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA maybe_kind = find_kind(string(e.head)) st_k = isnothing(maybe_kind) ? K"None" : maybe_kind st_flags = 0x0000 - child_exprs = copy(e.args) + child_exprs::Vector{Any} = copy(e.args) # The following are special cases where the kind, flags, or children are # different from what we guessed above. @@ -247,9 +247,21 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA # Existing behaviour appears to just ignore any extra args return _insert_convert_expr(e.args[1], graph, src) elseif e.head === :meta - @assert nargs <= 2 @assert e.args[1] isa Symbol - child_exprs[1] = Expr(:sym_not_identifier, e.args[1]) + if e.args[1] === :nospecialize + if nargs > 2 + st_k = K"block" + # Kick the can down the road + child_exprs = map(c->Expr(:meta, :nospecialize, c), child_exprs[2:end]) + else + st_id, src = _insert_convert_expr(e.args[2], graph, src) + setmeta!(SyntaxTree(graph, st_id); nospecialize=true) + return st_id, src + end + else + @assert nargs === 1 + child_exprs[1] = Expr(:sym_not_identifier, e.args[1]) + end elseif e.head === Symbol("'") @assert nargs === 1 st_k = K"call" @@ -394,6 +406,13 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA st_flags |= JS.NON_TERMINAL_FLAG st_id = _insert_tree_node(graph, st_k, src, st_flags) + st_child_ids, last_src = _insert_expr_children(child_exprs, graph, src) + setchildren!(graph, st_id, st_child_ids) + return st_id, last_src +end + +function _insert_expr_children(child_exprs::Vector{Any}, graph::SyntaxGraph, + src::SourceAttrType) st_child_ids = NodeId[] last_src = src for c in child_exprs @@ -401,7 +420,5 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA isnothing(c_id) || push!(st_child_ids, c_id) last_src = something(c_src, src) end - - setchildren!(graph, st_id, st_child_ids) - return (st_id, last_src) + return st_child_ids, last_src end diff --git a/src/syntax_graph.jl b/src/syntax_graph.jl index 0a08d598..b10e7d0e 100644 --- a/src/syntax_graph.jl +++ b/src/syntax_graph.jl @@ -246,13 +246,17 @@ function attrnames(ex::SyntaxTree) [name for (name, value) in pairs(attrs) if haskey(value, ex._id)] end -function setattr(ex::SyntaxTree; extra_attrs...) +function copy_node(ex::SyntaxTree) graph = syntax_graph(ex) id = newnode!(graph) if !is_leaf(ex) setchildren!(graph, id, _node_ids(graph, children(ex)...)) end - ex2 = SyntaxTree(graph, id) + SyntaxTree(graph, id) +end + +function setattr(ex::SyntaxTree; extra_attrs...) + ex2 = copy_node(ex) copy_attrs!(ex2, ex, true) setattr!(ex2; extra_attrs...) ex2 From ca66fb3ccbf5002d41060ede039c78a79b2955a5 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Fri, 11 Jul 2025 13:18:30 -0700 Subject: [PATCH 28/35] symboliclabel, symbolicgoto --- src/compat.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/compat.jl b/src/compat.jl index ff954e5a..d61dd824 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -247,11 +247,12 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA # Existing behaviour appears to just ignore any extra args return _insert_convert_expr(e.args[1], graph, src) elseif e.head === :meta + # Messy and undocumented. Sometimes we want a K"meta". @assert e.args[1] isa Symbol if e.args[1] === :nospecialize if nargs > 2 st_k = K"block" - # Kick the can down the road + # Kick the can down the road (should only be simple atoms?) child_exprs = map(c->Expr(:meta, :nospecialize, c), child_exprs[2:end]) else st_id, src = _insert_convert_expr(e.args[2], graph, src) @@ -374,6 +375,12 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA st_k = K"=" elseif e.head === Symbol("latestworld-if-toplevel") st_k = K"latestworld_if_toplevel" + elseif e.head === :symbolicgoto || e.head === :symboliclabel + @assert nargs === 1 + st_k = e.head === :symbolicgoto ? K"symbolic_label" : K"symbolic_goto" + st_id = _insert_tree_node(graph, st_k, src) + setattr!(graph, st_id, name_val=string(e.args[1])) + return (st_id, src) end # Temporary heads introduced by converting the parent expr From 98a05bdac363c365c880280fe29da41c7254174f Mon Sep 17 00:00:00 2001 From: Em Chu Date: Fri, 11 Jul 2025 13:54:59 -0700 Subject: [PATCH 29/35] Fix `setattr!` --- src/syntax_graph.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/syntax_graph.jl b/src/syntax_graph.jl index b10e7d0e..e5948da1 100644 --- a/src/syntax_graph.jl +++ b/src/syntax_graph.jl @@ -252,12 +252,13 @@ function copy_node(ex::SyntaxTree) if !is_leaf(ex) setchildren!(graph, id, _node_ids(graph, children(ex)...)) end - SyntaxTree(graph, id) + ex2 = SyntaxTree(graph, id) + copy_attrs!(ex2, ex, true) + ex2 end function setattr(ex::SyntaxTree; extra_attrs...) ex2 = copy_node(ex) - copy_attrs!(ex2, ex, true) setattr!(ex2; extra_attrs...) ex2 end From 2c24aa580beba19ac5bf3551d362560410b4df21 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Fri, 11 Jul 2025 14:24:12 -0700 Subject: [PATCH 30/35] Reorganize some cases; handle ``:[no]inline` --- src/compat.jl | 52 +++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/src/compat.jl b/src/compat.jl index d61dd824..eadf2ca7 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -242,27 +242,6 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA end # TODO node->expr handles do blocks here? - elseif e.head === :escape || e.head === Symbol("hygienic-scope") - @assert nargs >= 1 - # Existing behaviour appears to just ignore any extra args - return _insert_convert_expr(e.args[1], graph, src) - elseif e.head === :meta - # Messy and undocumented. Sometimes we want a K"meta". - @assert e.args[1] isa Symbol - if e.args[1] === :nospecialize - if nargs > 2 - st_k = K"block" - # Kick the can down the road (should only be simple atoms?) - child_exprs = map(c->Expr(:meta, :nospecialize, c), child_exprs[2:end]) - else - st_id, src = _insert_convert_expr(e.args[2], graph, src) - setmeta!(SyntaxTree(graph, st_id); nospecialize=true) - return st_id, src - end - else - @assert nargs === 1 - child_exprs[1] = Expr(:sym_not_identifier, e.args[1]) - end elseif e.head === Symbol("'") @assert nargs === 1 st_k = K"call" @@ -373,14 +352,43 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA (e)->(e.head = :importpath)) elseif e.head === :kw st_k = K"=" - elseif e.head === Symbol("latestworld-if-toplevel") + end + + # The following heads are not emitted from parsing, but old macros could + # produce these and they would historically be accepted by flisp lowering. + if e.head === Symbol("latestworld-if-toplevel") st_k = K"latestworld_if_toplevel" + elseif e.head === :escape || e.head === Symbol("hygienic-scope") + @assert nargs >= 1 + # Existing behaviour appears to just ignore any extra args + return _insert_convert_expr(e.args[1], graph, src) + elseif e.head === :meta + # Messy and undocumented. Sometimes we want a K"meta". + @assert e.args[1] isa Symbol + if e.args[1] === :nospecialize + if nargs > 2 + st_k = K"block" + # Kick the can down the road (should only be simple atoms?) + child_exprs = map(c->Expr(:meta, :nospecialize, c), child_exprs[2:end]) + else + st_id, src = _insert_convert_expr(e.args[2], graph, src) + setmeta!(SyntaxTree(graph, st_id); nospecialize=true) + return st_id, src + end + else + @assert nargs === 1 + child_exprs[1] = Expr(:sym_not_identifier, e.args[1]) + end elseif e.head === :symbolicgoto || e.head === :symboliclabel @assert nargs === 1 st_k = e.head === :symbolicgoto ? K"symbolic_label" : K"symbolic_goto" st_id = _insert_tree_node(graph, st_k, src) setattr!(graph, st_id, name_val=string(e.args[1])) return (st_id, src) + elseif e.head === :inline || e.head === :noinline + @assert nargs === 1 && e.args[1] isa Bool + # TODO: JuliaLowering doesn't accept this (non-:meta) form yet + return (nothing, src) end # Temporary heads introduced by converting the parent expr From bf07c558556baec1350726b8973f4cab87e1a281 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Mon, 14 Jul 2025 16:44:32 -0700 Subject: [PATCH 31/35] Support :flatten --- src/compat.jl | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/compat.jl b/src/compat.jl index eadf2ca7..2791e56b 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -294,8 +294,18 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA push!(child_exprs, Expr(:finally, e.args[4] === false ? nothing : e.args[4])) end - elseif e.head === :generator # TODO flatten - child_exprs = [e.args[1], _to_iterspec(e.args[2:end])] + elseif e.head === :flatten || e.head === :generator + st_k = K"generator" + child_exprs = Any[] + next = e + while next.head === :flatten + @assert next.args[1].head === :generator + push!(child_exprs, _to_iterspec(next.args[1].args[2:end])) + next = next.args[1].args[1] + end + @assert next.head === :generator + push!(child_exprs, _to_iterspec(next.args[2:end])) + pushfirst!(child_exprs, next.args[1]) elseif e.head === :ncat || e.head === :nrow st_flags |= JS.set_numeric_flags(e.args[1]) child_exprs = child_exprs[2:end] From 44e54b9f6cc60e7a6087fb167aada040adeaa274 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Tue, 15 Jul 2025 20:58:33 -0700 Subject: [PATCH 32/35] Small tweaks --- src/compat.jl | 16 +++++++--------- src/kinds.jl | 3 +++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/compat.jl b/src/compat.jl index 2791e56b..ceea7733 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -20,15 +20,15 @@ Expr-producing macros. Always prefer re-parsing source text over using this. Supports parsed and/or macro-expanded exprs, but not lowered exprs """ function expr_to_syntaxtree(@nospecialize(e), - mctx::Union{MacroExpansionContext, Nothing}=nothing, - lnn::Union{LineNumberNode, Nothing}=nothing) - graph = if isnothing(mctx) + lnn::Union{LineNumberNode, Nothing}=nothing, + ctx=nothing) + graph = if isnothing(ctx) ensure_attributes!(SyntaxGraph(), kind=Kind, syntax_flags=UInt16, source=SourceAttrType, var_id=Int, value=Any, name_val=String, is_toplevel_thunk=Bool) else - mctx.graph + syntax_graph(ctx) end toplevel_src = if isnothing(lnn) # Provenance sinkhole for all nodes until we hit a linenode @@ -154,7 +154,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA return (st_id, src) elseif e isa Symbol st_id = _insert_tree_node(graph, K"Identifier", src) - setattr!(graph, st_id, name_val=String(e)) + setattr!(graph, st_id; name_val=String(e)) if !Base.isoperator(e) && !Base.is_valid_identifier(e) return _insert_var_str(st_id, graph, src) end @@ -368,10 +368,8 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA # produce these and they would historically be accepted by flisp lowering. if e.head === Symbol("latestworld-if-toplevel") st_k = K"latestworld_if_toplevel" - elseif e.head === :escape || e.head === Symbol("hygienic-scope") - @assert nargs >= 1 - # Existing behaviour appears to just ignore any extra args - return _insert_convert_expr(e.args[1], graph, src) + elseif e.head === Symbol("hygienic-scope") + st_k = K"hygienic_scope" elseif e.head === :meta # Messy and undocumented. Sometimes we want a K"meta". @assert e.args[1] isa Symbol diff --git a/src/kinds.jl b/src/kinds.jl index 741307ba..0ccf145f 100644 --- a/src/kinds.jl +++ b/src/kinds.jl @@ -49,6 +49,9 @@ function _register_kinds() # Internal initializer for struct types, for inner constructors/functions "new" "splatnew" + # For expr-macro compatibility; gone after expansion + "escape" + "hygienic_scope" # Catch-all for additional syntax extensions without the need to # extend `Kind`. Known extensions include: # locals, islocal From 96e83c25d9e0ffeee285658d0d014a96d66990b1 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Thu, 17 Jul 2025 09:36:09 -0700 Subject: [PATCH 33/35] Support Expr(:core) --- src/compat.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/compat.jl b/src/compat.jl index ceea7733..9a9b882b 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -397,6 +397,13 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA @assert nargs === 1 && e.args[1] isa Bool # TODO: JuliaLowering doesn't accept this (non-:meta) form yet return (nothing, src) + elseif e.head === :core + @assert nargs === 1 + @assert e.args[1] isa Symbol + coreref_name = string(e.args[1]) + st_id = _insert_tree_node(graph, K"core", src) + setattr!(graph, st_id; name_val=coreref_name) + return st_id, src end # Temporary heads introduced by converting the parent expr From ab1768fb3002a0edb2e3e037421334c0744f0eac Mon Sep 17 00:00:00 2001 From: Em Chu Date: Fri, 18 Jul 2025 10:28:42 -0700 Subject: [PATCH 34/35] Fix some logic bugs from testing --- src/compat.jl | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/compat.jl b/src/compat.jl index 9a9b882b..21edff15 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -86,7 +86,7 @@ e.g. orderings of (a,b,c;d;e;f): """ function collect_expr_parameters(e::Expr, pos::Int) params = expr_parameters(e, pos) - isnothing(params) && return e.args + isnothing(params) && return copy(e.args) args = Any[e.args[1:pos-1]..., e.args[pos+1:end]...] return _flatten_params!(args, params) end @@ -140,6 +140,11 @@ function _insert_var_str(child::NodeId, graph::SyntaxGraph, src::SourceAttrType) return (var_id, src) end +function is_call_expr(e) + return e isa Expr && (e.head === :call || + e.head in (:where, :(::)) && is_call_expr(e.args[1])) +end + """ Insert `e` converted to a syntaxtree into graph and recurse on children. Return a pair (my_node_id, last_srcloc). Should not mutate `e`. @@ -174,7 +179,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA return (st_id, src) elseif !(e isa Expr) if !(e isa Union{Number, Bool, Char, GlobalRef, Nothing}) - @info "unknown leaf type in expr, guessing value:" e typeof(e) + # @info "unknown leaf type in expr, guessing value:" e typeof(e) end # TODO: st_k of Float. others? st_k = e isa Integer ? K"Integer" : find_kind(string(typeof(e))) @@ -314,7 +319,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA deleteat!(child_exprs, 2) elseif e.head === :(->) @assert nargs === 2 - if e.args[1] isa Symbol + if !(e.args[1] isa Expr && e.args[1].head === :tuple) child_exprs[1] = Expr(:tuple, e.args[1]) end child_exprs[2] = maybe_strip_block(e.args[2]) @@ -330,7 +335,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA end end elseif e.head === :(=) - if e.args[1] isa Expr && e.args[1].head === :call + if is_call_expr(e.args[1]) st_k = K"function" st_flags |= JS.SHORT_FORM_FUNCTION_FLAG child_exprs[2] = maybe_strip_block(child_exprs[2]) @@ -349,7 +354,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA st_k = K"call" child_exprs = [e.args[1].args..., Expr(:do_lambda, e.args[2].args...)] elseif e.head === :let - if nargs >= 1 && e.args[1] isa Expr && e.args[1].head !== :block + if nargs >= 1 && !(e.args[1] isa Expr && e.args[1].head === :block) child_exprs[1] = Expr(:block, e.args[1]) end elseif e.head === :struct From 247d4258b0138673a1ae080781cd250f66c34a16 Mon Sep 17 00:00:00 2001 From: Em Chu Date: Fri, 18 Jul 2025 15:34:09 -0700 Subject: [PATCH 35/35] :islocal, :isglobal --- src/compat.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/compat.jl b/src/compat.jl index 21edff15..d177e26d 100644 --- a/src/compat.jl +++ b/src/compat.jl @@ -409,6 +409,9 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA st_id = _insert_tree_node(graph, K"core", src) setattr!(graph, st_id; name_val=coreref_name) return st_id, src + elseif e.head === :islocal || e.head === :isglobal + st_k = K"extension" + child_exprs = [Expr(:sym_not_identifier, e.head), e.args[1]] end # Temporary heads introduced by converting the parent expr