From 0f269668c468ff6a2876221cdb21dfd78defb68c Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 15 Jun 2023 02:07:56 -0400 Subject: [PATCH] Make sure Core.Compiler can throw kwarg mismatch errors (#50174) The _new_NamedTuple helper was in a Base-only branch, causing ``` julia> Core.eval(Core.Compiler, quote f(;a=1) = a end) f (generic function with 1 method) julia> Core.Compiler.f(;b=2) ERROR: UndefVarError: `_new_NamedTuple` not defined Stacktrace: [1] macro expansion @ Core.Compiler ./namedtuple.jl:0 [inlined] [2] structdiff(a::@NamedTuple{b::Int64}, b::Type{NamedTuple{(:a,)}}) @ Core.Compiler ./namedtuple.jl:421 [3] top-level scope @ REPL[2]:1 ``` After this change, we have the expected ``` julia> Core.eval(Core.Compiler, quote f(;a=1) = a end) f (generic function with 1 method) julia> Core.Compiler.f(;b=2) ERROR: MethodError: no method matching f(; b::Int64) Closest candidates are: f(; a) got unsupported keyword argument "b" @ Core REPL[13]:1 Stacktrace: [1] kwerr(kw::@NamedTuple{b::Int64}, args::Function) @ Core.Compiler ./error.jl:165 [2] top-level scope @ REPL[14]:1 ``` --- base/namedtuple.jl | 12 ++++++------ test/compiler/AbstractInterpreter.jl | 5 +++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/base/namedtuple.jl b/base/namedtuple.jl index 5f6bdefbefd75..e489508bc55ea 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -133,12 +133,6 @@ function NamedTuple{names, T}(nt::NamedTuple) where {names, T <: Tuple} end end -# Like NamedTuple{names, T} as a constructor, but omits the additional -# `convert` call, when the types are known to match the fields -@eval function _new_NamedTuple(T::Type{NamedTuple{NTN, NTT}} where {NTN, NTT}, args::Tuple) - $(Expr(:splatnew, :T, :args)) -end - function NamedTuple{names}(nt::NamedTuple) where {names} if @generated idx = Int[ fieldindex(nt, names[n]) for n in 1:length(names) ] @@ -161,6 +155,12 @@ NamedTuple{names, Union{}}(itr::Tuple) where {names} = throw(MethodError(NamedTu end # if Base +# Like NamedTuple{names, T} as a constructor, but omits the additional +# `convert` call, when the types are known to match the fields +@eval function _new_NamedTuple(T::Type{NamedTuple{NTN, NTT}} where {NTN, NTT}, args::Tuple) + $(Expr(:splatnew, :T, :args)) +end + length(t::NamedTuple) = nfields(t) iterate(t::NamedTuple, iter=1) = iter > nfields(t) ? nothing : (getfield(t, iter), iter + 1) rest(t::NamedTuple) = t diff --git a/test/compiler/AbstractInterpreter.jl b/test/compiler/AbstractInterpreter.jl index 0e94d42fa8866..2cac29e76098b 100644 --- a/test/compiler/AbstractInterpreter.jl +++ b/test/compiler/AbstractInterpreter.jl @@ -348,3 +348,8 @@ let NoinlineModule = Module() @test count(iscall((src, inlined_usually)), src.code) == 0 end end + +# Make sure that Core.Compiler has enough NamedTuple infrastructure +# to properly give error messages for basic kwargs... +Core.eval(Core.Compiler, quote f(;a=1) = a end) +@test_throws MethodError Core.Compiler.f(;b=2)