@@ -1037,11 +1037,11 @@ end
10371037The trait to inject code into JuliaInterpreter's interpretation process; JET.jl overloads:
10381038- `JuliaInterpreter.step_expr!` to add error report pass for module usage expressions and
10391039 support package analysis
1040- - `JuliaInterpreter.evaluate_call_recurse !` to special case `include` calls
1040+ - `JuliaInterpreter.evaluate_call !` to special case `include` calls
10411041- `JuliaInterpreter.handle_err` to wrap an error happened during interpretation into
10421042 `ActualErrorWrapped`
10431043"""
1044- struct ConcreteInterpreter{F,Analyzer<: AbstractAnalyzer }
1044+ struct ConcreteInterpreter{F,Analyzer<: AbstractAnalyzer } <: Interpreter
10451045 filename:: String
10461046 lnn:: LineNumberNode
10471047 usemodule_with_err_handling:: F
@@ -1195,7 +1195,7 @@ function is_known_getproperty(@nospecialize(stmt), func::Symbol, stmts::Vector{A
11951195 if (callee_matches(f, Base, :getproperty) ||
11961196 callee_matches(f, Core, :getproperty) ||
11971197 callee_matches(f, CC, :getproperty))
1198- if is_quotenode_egal(stmt. args[3 ], func)
1198+ if JuliaInterpreter . is_quotenode_egal(stmt. args[3 ], func)
11991199 return true
12001200 end
12011201 end
@@ -1289,7 +1289,7 @@ function JuliaInterpreter.step_expr!(interp::ConcreteInterpreter, frame::Frame,
12891289 return frame. pc += 1
12901290 end
12911291
1292- res = @invoke JuliaInterpreter. step_expr!(interp:: Any , frame:: Frame , node:: Any , istoplevel:: Bool )
1292+ res = @invoke JuliaInterpreter. step_expr!(interp:: Interpreter , frame:: Frame , node:: Any , istoplevel:: Bool )
12931293
12941294 should_analyze_from_definitions(interp. config) && collect_toplevel_signature!(interp, frame, node)
12951295
@@ -1360,28 +1360,27 @@ function _to_simple_module_usages(x::Expr)
13601360 return Expr[Expr(x. head, ex) for ex in Expr[Expr(arg. head, a, a′) for a′ in as]]
13611361end
13621362
1363- # adapted from https://github.com/JuliaDebug/JuliaInterpreter.jl/blob/2f5f80034bc287a60fe77c4e3b5a49a087e38f8b/src/interpret.jl#L188-L199
1364- # works almost same as `JuliaInterpreter.evaluate_call_compiled!`, but with few important tweaks:
1365- # - a special handling for `include` call to recursively apply JET's analysis on the included file
1366- # - some `@invokelatest` are added where we directly call an user expression
1367- # since `_virtual_process!` iteratively interprets toplevel expressions but the world age
1368- # is not updated at each iteration so we need to make sure the user expression is
1369- # evaluated in the latest world age where newly defined functions are available .
1370- function JuliaInterpreter. evaluate_call_recurse !(interp:: ConcreteInterpreter , frame:: Frame , call_expr:: Expr ; enter_generated:: Bool = false )
1363+ # This overload performs almost the same work as
1364+ # `JuliaInterpreter.evaluate_call!(::JuliaInterpreter.NonRecursiveInterpreter, ...)`
1365+ # but includes a few important adjustments specific to JET's virtual process:
1366+ # - Special handling for `include` calls: recursively apply JET analysis to included files.
1367+ # - Ignore C-side function definitions created via `Base._ccallable`. These definitions
1368+ # are not namespaced in the module and can cause false-positive name conflict errors
1369+ # when running analysis multiple times (see aviatesk/JET.jl#597) .
1370+ function JuliaInterpreter. evaluate_call !(interp:: ConcreteInterpreter , frame:: Frame , call_expr:: Expr , enter_generated:: Bool )
13711371 # @assert !enter_generated
13721372 pc = frame. pc
13731373 ret = JuliaInterpreter. bypass_builtins(interp, frame, call_expr, pc)
13741374 isa(ret, Some{Any}) && return ret. value
1375- ret = @invokelatest JuliaInterpreter. maybe_evaluate_builtin(frame, call_expr, false )
1375+ ret = JuliaInterpreter. maybe_evaluate_builtin(interp, frame, call_expr, false )
13761376 isa(ret, Some{Any}) && return ret. value
13771377 args = JuliaInterpreter. collect_args(interp, frame, call_expr)
13781378 f = popfirst!(args) # now it's really just `args`
13791379 isinclude(f) && return handle_include(interp, f, args)
13801380 if f === Base. _ccallable
1381- # skip concrete-interpretation of `jl_extern_c` as the C-side function definition
1382- # isn't really essential for Julia-level analysis
1381+ # skip concrete-interpretation of `jl_extern_c`
13831382 if length(args) == 2 && args[1 ] isa Type && args[2 ] isa Type
1384- # ignore it only if the method dispatch is successful
1383+ # ignore only if the method dispatch is successful
13851384 return nothing
13861385 else
13871386 # otherwise just call it to trigger a method error
@@ -1469,7 +1468,7 @@ function JuliaInterpreter.handle_err(interp::ConcreteInterpreter, frame::Frame,
14691468
14701469 # if the last error is from this file, it's likely to be a serious error of JET
14711470 lastframe = last(st)
1472- if lastframe. file === JET_VIRTUALPROCESS_FILE && lastframe. func === :evaluate_call_recurse !
1471+ if lastframe. file === JET_VIRTUALPROCESS_FILE && lastframe. func === :evaluate_call !
14731472 rethrow(err)
14741473 end
14751474
@@ -1483,9 +1482,9 @@ function JuliaInterpreter.handle_err(interp::ConcreteInterpreter, frame::Frame,
14831482 end
14841483
14851484 # find an error frame that happened at `@invokelatest f(fargs...)` in the overload
1486- # `JuliaInterpreter.evaluate_call_recurse!(interp ::ConcreteInterpreter, frame ::Frame, call_expr ::Expr; enter_generated ::Bool=false )`
1487- if frame. file === JET_VIRTUALPROCESS_FILE && frame. func === :evaluate_call_recurse !
1488- i = j - 2 # offset: `evaluate_call_recurse` -> kwfunc (`evaluate_call_recurse`)
1485+ # `JuliaInterpreter.evaluate_call!( ::ConcreteInterpreter, ::Frame, ::Expr, ::Bool)`
1486+ if frame. file === JET_VIRTUALPROCESS_FILE && frame. func === :evaluate_call !
1487+ i = j - 1 # offset: `evaluate_call!`
14891488 break
14901489 end
14911490
0 commit comments