Skip to content

Commit

Permalink
Fix getfield_tfunc for constant TypeName (#37443)
Browse files Browse the repository at this point in the history
The field should be either `Symbol` or `Int`. Ref #37423

Unlike #37423, in additional to worse type info in inference,
the missing type check here can actually cause type inference error
due to errors in user code.

(cherry picked from commit 1378bb6)
  • Loading branch information
yuyichao authored and JeffBezanson committed Sep 9, 2020
1 parent 4ea0e8c commit 63aa793
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 3 deletions.
6 changes: 3 additions & 3 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,9 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name))
end
if isa(name, Const)
nv = name.val
if !(isa(nv,Symbol) || isa(nv,Int))
return Bottom
end
if isa(sv, UnionAll)
if nv === :var || nv === 1
return Const(sv.var)
Expand All @@ -755,9 +758,6 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name))
if isa(sv, Module) && isa(nv, Symbol)
return abstract_eval_global(sv, nv)
end
if !(isa(nv,Symbol) || isa(nv,Int))
return Bottom
end
if (isa(sv, SimpleVector) || !ismutable(sv)) && isdefined(sv, nv)
return AbstractEvalConstant(getfield(sv, nv))
end
Expand Down
22 changes: 22 additions & 0 deletions test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2625,3 +2625,25 @@ f36531(args...) = tuple((args...)...)
@test (sizeof(Ptr),) == sizeof.((Ptr,)) == sizeof.((Ptr{Cvoid},))
@test Core.Compiler.sizeof_tfunc(UnionAll) === Int
@test !Core.Compiler.sizeof_nothrow(UnionAll)

# Use a global constant to rely less on unrelated constant propagation
const const_int32_typename = Int32.name
# Check constant propagation for field of constant `TypeName`
# works for both valid and invalid field names. (Ref #37443)
getfield_const_typename_good1() = getfield(const_int32_typename, 1)
getfield_const_typename_good2() = getfield(const_int32_typename, :name)
getfield_const_typename_bad1() = getfield(const_int32_typename, 0x1)
@eval getfield_const_typename_bad2() = getfield(const_int32_typename, $(()))
for goodf in [getfield_const_typename_good1, getfield_const_typename_good2]
local goodf
local code = code_typed(goodf, Tuple{})[1].first.code
@test code[1] == Expr(:return, QuoteNode(:Int32))
@test goodf() === :Int32
end
for badf in [getfield_const_typename_bad1, getfield_const_typename_bad2]
local badf
local code = code_typed(badf, Tuple{})[1].first.code
@test Meta.isexpr(code[1], :call)
@test code[end] == Expr(:unreachable)
@test_throws TypeError badf()
end

0 comments on commit 63aa793

Please sign in to comment.