CassetteOverlay.jl
CassetteOverlay.jl copied to clipboard
Keyword arguments overlay not called
Ok I reduced my actual bug down to a MWE
using CassetteOverlay
struct ParamLens
end
function (🔍::ParamLens)(;kwargs...)
@show "ParamLens", kwargs
end
struct ParamInterp{M, S} <: CassetteOverlay.AbstractBindingOverlay{M, S}
end
function (self::ParamInterp)(lens::ParamLens; kwargs...)
@show "ParamInterp", kwargs
end
interp = ParamInterp{nothing, nothing}()
inst = ParamLens()
test1() = inst()
test1()
interp(test1)
test2() = inst(; foo=3)
test2()
interp(test2);
This prints
("ParamLens", kwargs) = ("ParamLens", Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}())
("ParamInterp", kwargs) = ("ParamInterp", Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}())
("ParamLens", kwargs) = ("ParamLens", Base.Pairs(:foo => 3))
("ParamLens", kwargs) = ("ParamLens", Base.Pairs(:foo => 3))
I would expect the last line to be ParamInterp but it just bypasses the method
function (self::ParamInterp)(lens::ParamLens; kwargs...)
@show "ParamInterp", kwargs
end
is not the expected interface for overlaying a method (and it does not make sense to execute code with this package if you do not use external method table).
You should do something like:
@MethodTable LensTable;
@overlay LensTable function (🔍::ParamLens)(;kwargs...)
@show "ParamInterp", kwargs
end
interp = ParamInterp{@__MODULE__, :LensTable}()
You can do something like
using CassetteOverlay
struct ParamLens end
function (🔍::ParamLens)(;kwargs...)
@show "ParamLens", kwargs
end
struct ParamInterp{M, S} <: CassetteOverlay.AbstractBindingOverlay{M, S} end
# HACK get the keyword sorter of `ParamLens()` and define the overlayed keyword method with it...
let src = only(code_lowered(ParamLens()))
call = src.code[end-1]
@assert Meta.isexpr(call, :call) && call.args[1] isa Core.GlobalRef
kwsorter = Core.Compiler.abstract_eval_globalref(call.args[1]::Core.GlobalRef).val
global function (interp::ParamInterp)(::Core.Typeof(kwsorter), kwargs::Base.pairs(NamedTuple), 🔍::ParamLens)
@show "ParamInterp", kwargs
end
end
interp = ParamInterp{nothing, nothing}()
const 🔍 = ParamLens()
test1() = 🔍()
test1()
interp(test1)
test2() = 🔍(; foo=3)
test2()
interp(test2);
After #34, you should switch to the following pattern:
using CassetteOverlay
struct ParamLens end
function (🔍::ParamLens)(; kwargs...)
@show "ParamLens", kwargs
nothing
end
@MethodTable ParamInterpTable
mutable struct ParamInterp <: AbstractBindingOverlay{@__MODULE__, :ParamInterpTable}
some_state
end
@overlay ParamInterpTable function (🔍::ParamLens)(; kwargs...)
@show "ParamLens", kwargs
@show "ParamInterp", getpass()
nothing
end
interp = ParamInterp(nothing)
const 🔍 = ParamLens()
test1() = 🔍()
test1()
interp(test1);
test2() = 🔍(; foo=3)
test2()
interp(test2);
Can you switch your use case to this pattern?
Yes this would work but the example you give fails with the following error on 0.1.6
julia> interp(test1);
ERROR: type DataType has no field body
It seems to be another bug.
Is there a fix for this bug on the horizon?
For the time being, you can define the following overload:
# a temporal fix for #33
@inline (::ParamInterp)(::typeof(Base.typename), @nospecialize args...) =
Base.typename(args...)
to circumvent the issue.
Hopefully we will not hit the root issue that often.
I opened a new issue #45 with a reduced example. Let's focus on this issue there.