Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions src/signatures.jl
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,19 @@ end
# try to normalize `def` to `GlobalRef` representation
function normalize_defsig(@nospecialize(def), mod::Module)
if def isa QuoteNode
# A quoted Symbol (e.g. the callee of `:foo(x)`) is already a name; only
# other wrapped values (functions, types, modules) need `nameof`.
def = def.value isa Symbol ? def.value : nameof(def.value)
val = def.value
if val isa Symbol
# A quoted Symbol (e.g. the callee of `:foo(x)`) is already a name.
def = val
elseif val isa Union{Function, DataType, UnionAll, Module}
# The quoted values that have a name (e.g. a `const` callee that
# JuliaInterpreter folded into a `QuoteNode`).
def = nameof(val)
else
# Any other quoted value, e.g. an instance of a callable struct that a macro
# interpolated as the callee of a call, is not a name: leave it as it is.
return def
end
end
if def isa Symbol
def = GlobalRef(mod, def)
Expand Down
31 changes: 31 additions & 0 deletions test/signatures.jl
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,37 @@ end
@test LoweredCodeUtils.identify_framemethod_calls(frame) isa Any # must not throw
end

# A callable value that is neither a function, a type nor a module: it has no `nameof`.
module QuotedCallee
struct Offset
value::Float64
end
(offset::Offset)(x) = x + offset.value
end

@testset "normalize_defsig with a quoted callable value as callee" begin
# A macro may interpolate an arbitrary value as the callee of a call,
# `$(QuoteNode(Offset(2.0)))(x)`, which lowers to a `:call` whose callee is that
# `QuoteNode`. Only functions, types and modules have a `nameof`; any other quoted
# value is not a name and must be left as it is instead of throwing.
for val in (QuotedCallee.Offset(2.0), 1, "s", Union{Int,String})
qn = QuoteNode(val)
@test LoweredCodeUtils.normalize_defsig(qn, QuotedCallee) === qn
end
for (val, name) in ((sum, :sum), (Int, :Int64), (Base, :Base))
@test LoweredCodeUtils.normalize_defsig(QuoteNode(val), QuotedCallee) === GlobalRef(QuotedCallee, name)
end

ex = :(apply_offset(x) = $(QuoteNode(QuotedCallee.Offset(2.0)))(x))
methodinfos, selfcalls = LoweredCodeUtils.identify_framemethod_calls(Frame(QuotedCallee, ex))
@test haskey(methodinfos, GlobalRef(QuotedCallee, :apply_offset))
@test isempty(selfcalls)
signatures = MethodInfoKey[]
methoddefs!(signatures, Frame(QuotedCallee, ex))
@test length(signatures) == 1
@test Base.invokelatest(QuotedCallee.apply_offset, 3.0) == 5.0
end

module FoldedCallees
struct Callable end
end
Expand Down