@@ -24,22 +24,23 @@ const no_default_value = NoDefaultValue()
2424# These are TypedSyntaxNode constructor helpers
2525# Call these directly if you want both the TypedSyntaxNode and the `mappings` list,
2626# where `mappings[i]` corresponds to the list of nodes matching `(src::CodeInfo).code[i]`.
27- function tsn_and_mappings (@nospecialize (f), @nospecialize (t); kwargs... )
28- m = which (f, t)
29- src, rt = getsrc (f, t)
30- tsn_and_mappings (m, src, rt; kwargs... )
27+ function tsn_and_mappings (@nospecialize (f), @nospecialize (tt= Base. default_tt (f)); kwargs... )
28+ inferred_result = get_inferred_result (f, tt)
29+ return tsn_and_mappings (inferred_result. mi, inferred_result. src, inferred_result. rt; kwargs... )
3130end
3231
33- function tsn_and_mappings (m:: Method , src:: CodeInfo , @nospecialize (rt); warn:: Bool = true , strip_macros:: Bool = false , kwargs... )
32+ function tsn_and_mappings (mi:: MethodInstance , src:: CodeInfo , @nospecialize (rt); warn:: Bool = true , strip_macros:: Bool = false , kwargs... )
33+ m = mi. def:: Method
3434 def = definition (String, m)
3535 if isnothing (def)
3636 warn && @warn " couldn't retrieve source of $m "
3737 return nothing , nothing
3838 end
39- return tsn_and_mappings (m , src, rt, def... ; warn, strip_macros, kwargs... )
39+ return tsn_and_mappings (mi , src, rt, def... ; warn, strip_macros, kwargs... )
4040end
4141
42- function tsn_and_mappings (m:: Method , src:: CodeInfo , @nospecialize (rt), sourcetext:: AbstractString , lineno:: Integer ; warn:: Bool = true , strip_macros:: Bool = false , kwargs... )
42+ function tsn_and_mappings (mi:: MethodInstance , src:: CodeInfo , @nospecialize (rt), sourcetext:: AbstractString , lineno:: Integer ; warn:: Bool = true , strip_macros:: Bool = false , kwargs... )
43+ m = mi. def:: Method
4344 filename = isnothing (functionloc (m)[1 ]) ? string (m. file) : functionloc (m)[1 ]
4445 rootnode = JuliaSyntax. parsestmt (SyntaxNode, sourcetext; filename= filename, first_line= lineno, kwargs... )
4546 if strip_macros
@@ -50,22 +51,26 @@ function tsn_and_mappings(m::Method, src::CodeInfo, @nospecialize(rt), sourcetex
5051 end
5152 end
5253 Δline = lineno - m. line # offset from original line number (Revise)
53- mappings, symtyps = map_ssas_to_source (src, rootnode, Δline)
54+ mappings, symtyps = map_ssas_to_source (src, mi, rootnode, Δline)
5455 node = TypedSyntaxNode (rootnode, src, mappings, symtyps)
5556 node. typ = rt
5657 return node, mappings
5758end
5859
59- TypedSyntaxNode (@nospecialize (f), @nospecialize (t) ; kwargs... ) = tsn_and_mappings (f, t ; kwargs... )[1 ]
60+ TypedSyntaxNode (@nospecialize (f), @nospecialize (tt = Base . default_tt (f)) ; kwargs... ) = tsn_and_mappings (f, tt ; kwargs... )[1 ]
6061
6162function TypedSyntaxNode (mi:: MethodInstance ; kwargs... )
62- m = mi. def:: Method
63- src, rt = getsrc (mi)
64- tsn_and_mappings (m, src, rt; kwargs... )[1 ]
63+ src, rt = code_typed1_tsn (mi)
64+ tsn_and_mappings (mi, src, rt; kwargs... )[1 ]
65+ end
66+
67+ function TypedSyntaxNode (rootnode:: SyntaxNode , @nospecialize (f), @nospecialize (tt= Base. default_tt (f)); kwargs... )
68+ inferred_result = get_inferred_result (f, tt)
69+ TypedSyntaxNode (rootnode, inferred_result. src, inferred_result. mi; kwargs... )
6570end
6671
67- TypedSyntaxNode (rootnode:: SyntaxNode , src:: CodeInfo , Δline:: Integer = 0 ) =
68- TypedSyntaxNode (rootnode, src, map_ssas_to_source (src, rootnode, Δline)... )
72+ TypedSyntaxNode (rootnode:: SyntaxNode , src:: CodeInfo , mi :: MethodInstance , Δline:: Integer = 0 ) =
73+ TypedSyntaxNode (rootnode, src, map_ssas_to_source (src, mi, rootnode, Δline)... )
6974
7075function TypedSyntaxNode (rootnode:: SyntaxNode , src:: CodeInfo , mappings, symtyps)
7176 # There may be ambiguous assignments back to the source; preserve just the unambiguous ones
@@ -304,17 +309,57 @@ function sparam_name(mi::MethodInstance, i::Int)
304309 return sig. var. name
305310end
306311
307- function getsrc (@nospecialize (f), @nospecialize (t))
308- srcrts = code_typed (f, t; debuginfo= :source , optimize= false )
309- return only (srcrts)
310- end
311-
312- function getsrc (mi:: MethodInstance )
313- cis = Base. code_typed_by_type (mi. specTypes; debuginfo= :source , optimize= false )
314- isempty (cis) && error (" no applicable type-inferred code found for " , mi)
315- length (cis) == 1 || error (" got $(length (cis)) possible type-inferred results for " , mi,
316- " , you may need a more specialized signature" )
317- return cis[1 ]:: Pair{CodeInfo}
312+ @static if isdefined (Base, :method_instances )
313+ using Base: method_instances
314+ else
315+ function method_instances (@nospecialize (f), @nospecialize (t), world:: UInt )
316+ tt = Base. signature_type (f, t)
317+ results = Core. MethodInstance[]
318+ # this make a better error message than the typeassert that follows
319+ world == typemax (UInt) && error (" code reflection cannot be used from generated functions" )
320+ for match in Base. _methods_by_ftype (tt, - 1 , world):: Vector
321+ instance = Core. Compiler. specialize_method (match)
322+ push! (results, instance)
323+ end
324+ return results
325+ end
326+ end
327+
328+ struct InferredResult
329+ mi:: MethodInstance
330+ src:: CodeInfo
331+ rt
332+ InferredResult (mi:: MethodInstance , src:: CodeInfo , @nospecialize (rt)) = new (mi, src, rt)
333+ end
334+ function get_inferred_result (@nospecialize (f), @nospecialize (tt= Base. default_tt (f)),
335+ world:: UInt = Base. get_world_counter ())
336+ mis = method_instances (f, tt, world)
337+ if isempty (mis)
338+ sig = sprint (Base. show_tuple_as_call, Symbol (" " ), Base. signature_type (f, tt))
339+ error (" no applicable type-inferred code found for " , sig)
340+ elseif length (mis) ≠ 1
341+ sig = sprint (Base. show_tuple_as_call, Symbol (" " ), Base. signature_type (f, tt))
342+ error (" got $(length (mis)) possible type-inferred results for " , sig,
343+ " , you may need a more specialized signature" )
344+ end
345+ mi = only (mis)
346+ return InferredResult (mi, code_typed1_tsn (mi)... )
347+ end
348+
349+ code_typed1_tsn (mi:: MethodInstance ) = code_typed1_by_method_instance (mi; optimize= false , debuginfo= :source )
350+
351+ function code_typed1_by_method_instance (mi:: MethodInstance ;
352+ optimize:: Bool = true ,
353+ debuginfo:: Symbol = :default ,
354+ world:: UInt = Base. get_world_counter (),
355+ interp:: Core.Compiler.AbstractInterpreter = Core. Compiler. NativeInterpreter (world))
356+ (ccall (:jl_is_in_pure_context , Bool, ()) || world == typemax (UInt)) &&
357+ error (" code reflection should not be used from generated functions" )
358+ debuginfo = Base. IRShow. debuginfo (debuginfo)
359+ code, rt = Core. Compiler. typeinf_code (interp, mi. def:: Method , mi. specTypes, mi. sparam_vals, optimize)
360+ code isa CodeInfo || error (" no code is available for " , mi)
361+ debuginfo === :none && Base. remove_linenums! (code)
362+ return Pair {CodeInfo,Any} (code, rt)
318363end
319364
320365function is_function_def (node) # this is not `Base.is_function_def`
397442# Main logic for mapping `src.code[i]` to node(s) in the SyntaxNode tree
398443# Success: when we map it to a unique node
399444# Δline is the (Revise) offset of the line number
400- function map_ssas_to_source (src:: CodeInfo , rootnode:: SyntaxNode , Δline:: Int )
401- mi = src. parent:: MethodInstance
445+ function map_ssas_to_source (src:: CodeInfo , mi:: MethodInstance , rootnode:: SyntaxNode , Δline:: Int )
402446 slottypes = src. slottypes:: Union{Nothing, Vector{Any}}
403447 have_slottypes = slottypes != = nothing
404448 ssavaluetypes = src. ssavaluetypes:: Vector{Any}
@@ -428,7 +472,7 @@ function map_ssas_to_source(src::CodeInfo, rootnode::SyntaxNode, Δline::Int)
428472 # (Essentially `copy!(mapped, filter(predicate, targets))`)
429473 function append_targets_for_line! (mapped#= ::Vector{nodes}=# , i:: Int , targets#= ::Vector{nodes}=# )
430474 j = src. codelocs[i]
431- lt = src. linetable:: Vector{Any}
475+ lt = src. linetable:: Vector
432476 start = getline (lt, j) + Δline
433477 stop = getnextline (lt, j, Δline) - 1
434478 linerange = start : stop
@@ -736,7 +780,7 @@ function map_ssas_to_source(src::CodeInfo, rootnode::SyntaxNode, Δline::Int)
736780 end
737781 return mappings, symtyps
738782end
739- map_ssas_to_source (src:: CodeInfo , rootnode:: SyntaxNode , Δline:: Integer ) = map_ssas_to_source (src, rootnode, Int (Δline))
783+ map_ssas_to_source (src:: CodeInfo , mi :: MethodInstance , rootnode:: SyntaxNode , Δline:: Integer ) = map_ssas_to_source (src, mi , rootnode, Int (Δline))
740784
741785function follow_back (src, arg)
742786 # Follow SSAValue backward to see if it maps back to a slot
0 commit comments