From 025d1062f9d2a1c61a21b1d4b9a48f0f1e3b0f2b Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Fri, 9 Oct 2020 06:28:32 +0900 Subject: [PATCH] compiler: more accurate `isdefined_tfunc` for `NamedTuple` arg: (#37830) e.g. this will exclude unnecessary runtime calls of `haskey` when a keyword argument is inferred as non-concrete type ```julia f(a; b = nothing, c = nothing) = return let b = rand((nothing,1,1.)) f(0; b) end ``` --- base/compiler/tfuncs.jl | 5 +++++ test/compiler/inference.jl | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 9e0cad564901f..f8db243ce4dae 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -287,6 +287,11 @@ function isdefined_tfunc(@nospecialize(arg1), @nospecialize(sym)) elseif a1.name === _NAMEDTUPLE_NAME if isconcretetype(a1) return Const(false) + else + ns = a1.parameters[1] + if isa(ns, Tuple) + return Const(1 <= idx <= length(ns)) + end end elseif idx <= 0 || (!isvatuple(a1) && idx > fieldcount(a1)) return Const(false) diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index b1b1ea5cf34cc..f0715472f172c 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -1072,6 +1072,16 @@ end @test isdefined_tfunc(Tuple{Any,Vararg{Any}}, Const(1)) === Const(true) @test isdefined_tfunc(Tuple{Any,Vararg{Any}}, Const(2)) === Bool @test isdefined_tfunc(Tuple{Any,Vararg{Any}}, Const(3)) === Bool +@testset "isdefined check for `NamedTuple`s" begin + # concrete `NamedTuple`s + @test isdefined_tfunc(NamedTuple{(:x,:y),Tuple{Int,Int}}, Const(:x)) === Const(true) + @test isdefined_tfunc(NamedTuple{(:x,:y),Tuple{Int,Int}}, Const(:y)) === Const(true) + @test isdefined_tfunc(NamedTuple{(:x,:y),Tuple{Int,Int}}, Const(:z)) === Const(false) + # non-concrete `NamedTuple`s + @test isdefined_tfunc(NamedTuple{(:x,:y),<:Tuple{Int,Any}}, Const(:x)) === Const(true) + @test isdefined_tfunc(NamedTuple{(:x,:y),<:Tuple{Int,Any}}, Const(:y)) === Const(true) + @test isdefined_tfunc(NamedTuple{(:x,:y),<:Tuple{Int,Any}}, Const(:z)) === Const(false) +end @noinline map3_22347(f, t::Tuple{}) = () @noinline map3_22347(f, t::Tuple) = (f(t[1]), map3_22347(f, Base.tail(t))...)