JuliaDebug / JuliaInterpreter.jl

Interpreter for Julia code
Other
162 stars 35 forks source link

Keyword arguments in @interpret are not properly evaluated #113

Closed KristofferC closed 5 years ago

KristofferC commented 5 years ago
> using Gadfly

> @interpret plot(y=[1,2,3])
ERROR: MethodError: no method matching evalmapping(::Nothing, ::Expr)
Closest candidates are:
  evalmapping(::Any, ::AbstractArray) at C:\Users\Kristoffer\.julia\packages\Gadfly\09PWZ\src\mapping.jl:185
  evalmapping(::Any, ::Function) at C:\Users\Kristoffer\.julia\packages\Gadfly\09PWZ\src\mapping.jl:186
  evalmapping(::Any, ::Distributions.Distribution) at C:\Users\Kristoffer\.julia\packages\Gadfly\09PWZ\src\mapping.jl:187
Stacktrace:
 [1] evalmapping!(::Dict{Symbol,Any}, ::Nothing, ::Gadfly.Data) at C:\Users\Kristoffer\.julia\packages\Gadfly\09PWZ\src\mapping.jl:220
 [2] plot at C:\Users\Kristoffer\.julia\packages\Gadfly\09PWZ\src\Gadfly.jl:327 [inlined]
 [3] #plot#66(::Base.Iterators.Pairs{Symbol,Expr,Tuple{Symbol},NamedTuple{(:y,),Tuple{Expr}}}, ::Function) at C:\Users\Kristoffer\.julia\packages\Gadfly\09PWZ\src\Gadfly.jl:308
 [4] maybe_evaluate_builtin(::JuliaStackFrame, ::Expr) at C:\Users\Kristoffer\Debugging\JuliaInterpreter\src\builtins-julia1.1.jl:42
 [5] #evaluate_call!#9(::typeof(JuliaInterpreter.finish_and_return!), ::Function, ::Array{JuliaStackFrame,1}, ::JuliaStackFrame, ::Expr, ::JuliaInterpreter.JuliaProgramCounter) at C:\Users\Kristoffer\Debugging\JuliaInterpreter\src\interpret.jl:191
 [6] evaluate_call!(::Array{JuliaStackFrame,1}, ::JuliaStackFrame, ::Expr, ::JuliaInterpreter.JuliaProgramCounter) at C:\Users\Kristoffer\Debugging\JuliaInterpreter\src\interpret.jl:182
 [7] eval_rhs(::Array{JuliaStackFrame,1}, ::JuliaStackFrame, ::Expr, ::JuliaInterpreter.JuliaProgramCounter) at C:\Users\Kristoffer\Debugging\JuliaInterpreter\src\interpret.jl:327
 [8] _step_expr!(::Array{JuliaStackFrame,1}, ::JuliaStackFrame, ::Any, ::JuliaInterpreter.JuliaProgramCounter, ::Bool) at C:\Users\Kristoffer\Debugging\JuliaInterpreter\src\interpret.jl:452
 [9] _step_expr!(::Array{JuliaStackFrame,1}, ::JuliaStackFrame, ::JuliaInterpreter.JuliaProgramCounter,
::Bool) at C:\Users\Kristoffer\Debugging\JuliaInterpreter\src\interpret.jl:478
 [10] finish!(::Array{JuliaStackFrame,1}, ::JuliaStackFrame, ::JuliaInterpreter.JuliaProgramCounter, ::Bool) at C:\Users\Kristoffer\Debugging\JuliaInterpreter\src\interpret.jl:530
 [11] finish_and_return!(::Array{JuliaStackFrame,1}, ::JuliaStackFrame, ::JuliaInterpreter.JuliaProgramCounter, ::Bool) at C:\Users\Kristoffer\Debugging\JuliaInterpreter\src\interpret.jl:558 (repeats 3 times)
 [12] top-level scope at C:\Users\Kristoffer\Debugging\JuliaInterpreter\src\JuliaInterpreter.jl:1128

Removing the @interpret and it works.

KristofferC commented 5 years ago

The difference is that at https://github.com/GiovineItalia/Gadfly.jl/blob/2cbd6d4ccd47125b2db8cb02f8a7e798c51c5bcc/src/Gadfly.jl#L310-L312

the variable mapping is in the interpreter case:

mapping = Base.Iterators.Pairs(:y=>:([1, 2, 3]))

while in the compiled case:

mapping = Base.Iterators.Pairs(:y=>[1, 2, 3])

Seems like it is spuriously wrapping an expression around the keyword argument value.

pfitzseb commented 5 years ago

MWE:

julia> f(;x) = x
f (generic function with 2 methods)

julia> @interpret f(;x=[1,2,3])
:([1, 2, 3])

julia> f(;x=[1,2,3])
3-element Array{Int64,1}:
 1
 2
 3
KristofferC commented 5 years ago

MMWE

> JuliaInterpreter.namedtuple( [:(x=1)])
(x = 1,)

> JuliaInterpreter.namedtuple( [:(x=[1,2,3])])
(x = :([1, 2, 3]),)

I think we perhaps need to eval the keyword argument in the module of the frame?

> g(; x = nothing) = x

> @interpret g(x = waowao(z))
:(waowao(z))
pfitzseb commented 5 years ago

It needs to be evaled in the scope of the call though:

julia> f(;x) = x
f (generic function with 2 methods)

julia> function g(x)
         y = sin(x)
         @interpret f(;x=asin(y))
       end
g (generic function with 1 method)

julia> g(1)
:(asin(y))
timholy commented 5 years ago

Our tech has evolved considerably beyond only supporting call expressions; how about we change the meaning of @interpret to the equivalent of

julia> ex = :(f(;x=[1,2,3]))
:(f(; x=[1, 2, 3]))

julia> frame = JuliaInterpreter.prepare_thunk(Main, ex)
JuliaStackFrame(JuliaInterpreter.JuliaFrameCode(Main, CodeInfo(
1 ─ %1 = ($(QuoteNode(tuple)))(:x)
│   %2 = ($(QuoteNode(Core.apply_type)))($(QuoteNode(NamedTuple)), %1)
│   %3 = ($(QuoteNode(Base.vect)))(1, 2, 3)
│   %4 = ($(QuoteNode(tuple)))(%3)
│   %5 = (%2)(%4)
│   %6 = ($(QuoteNode(Core.kwfunc)))(f)
│   %7 = (%6)(%5, f)
└──      return %7
), Union{Compiled, TypeMapEntry}[#undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef], JuliaInterpreter.BreakpointState[#undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef], BitSet([1, 2, 3, 4, 5, 6, 7]), false, false, true), Union{Nothing, Some{Any}}[], Any[#undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef], Any[], Int64[], Base.RefValue{Any}(nothing), Base.RefValue{JuliaInterpreter.JuliaProgramCounter}(JuliaProgramCounter(1)), Dict{Symbol,Int64}(), Any[])

julia> JuliaInterpreter.finish_and_return!(JuliaStackFrame[], frame)
3-element Array{Int64,1}:
 1
 2
 3