Skip to content

Commit

Permalink
fix pkgeval
Browse files Browse the repository at this point in the history
  • Loading branch information
aviatesk committed Aug 15, 2024
1 parent 0380a60 commit 032510c
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 54 deletions.
19 changes: 16 additions & 3 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2030,7 +2030,13 @@ function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, (; fargs
else
thentype = form_partially_defined_struct(argtype2, argtypes[3])
if thentype !== nothing
return Conditional(a, thentype, argtype2)
elsetype = argtype2
if rt === Const(false)
thentype = Bottom
elseif rt === Const(true)
elsetype = Bottom
end
return Conditional(a, thentype, elsetype)
end
end
end
Expand All @@ -2045,10 +2051,16 @@ function form_partially_defined_struct(@nospecialize(obj), @nospecialize(name))
name isa Const || return nothing
objt0 = widenconst(obj)
objt = unwrap_unionall(objt0)
objt isa DataType || return nothing
isabstracttype(objt) && return nothing
fldidx = try_compute_fieldidx(objt, name.val)
fldidx === nothing && return nothing
fldidx datatype_min_ninitialized(objt) && return nothing
nminfld = datatype_min_ninitialized(objt)
if ismutabletype(objt)
fldidx == nminfld+1 || return nothing
else
fldidx > nminfld || return nothing
end
return PartialStruct(objt0, Any[fieldtype(objt0, i) for i = 1:fldidx])
end

Expand Down Expand Up @@ -3111,7 +3123,8 @@ end
@nospecializeinfer function widenreturn_partials(𝕃ᵢ::PartialsLattice, @nospecialize(rt), info::BestguessInfo)
if isa(rt, PartialStruct)
fields = copy(rt.fields)
anyrefine = !isvarargtype(rt.fields[end]) && length(rt.fields) > datatype_min_ninitialized(rt.typ)
anyrefine = !isvarargtype(rt.fields[end]) &&
length(rt.fields) > datatype_min_ninitialized(unwrap_unionall(rt.typ))
𝕃 = typeinf_lattice(info.interp)
= strictpartialorder(𝕃)
for i in 1:length(fields)
Expand Down
13 changes: 5 additions & 8 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -419,30 +419,27 @@ end
else
return Bottom
end
if 1 <= idx <= datatype_min_ninitialized(a1)
if 1 idx datatype_min_ninitialized(a1)
return Const(true)
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))
return Const(1 idx length(ns))
end
end
elseif idx <= 0 || (!isvatuple(a1) && idx > fieldcount(a1))
elseif idx 0 || (!isvatuple(a1) && idx > fieldcount(a1))
return Const(false)
elseif isa(arg1, Const)
if !ismutabletype(a1) || isconst(a1, idx)
return Const(isdefined(arg1.val, idx))
end
elseif isa(arg1, PartialStruct)
nflds = length(arg1.fields)
if !isvarargtype(arg1.fields[end])
if 1 idx nflds
if 1 idx length(arg1.fields)
return Const(true)
elseif !ismutabletype(a1) || isconst(a1, idx)
return Const(false)
end
end
elseif !isvatuple(a1)
Expand Down Expand Up @@ -1005,7 +1002,7 @@ end
nflds = nfields(sv)
ismod = sv isa Module
elseif isa(s00, PartialStruct)
sty = s00.typ
sty = unwrap_unionall(s00.typ)
nflds = fieldcount_noerror(sty)
ismod = false
else
Expand Down
2 changes: 1 addition & 1 deletion base/compiler/typelattice.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ with `Int` values.
If `typ` is a struct, `fields` represents the fields of the struct that are guaranteed to be
initialized. For instance, if the length of `fields` of `PartialStruct` representing a
struct with 4 fields is 3, the 4th field may be uninitialized. If the length is four, all
struct with 4 fields is 3, the 4th field may not be initialized. If the length is 4, all
fields are guaranteed to be initialized.
If `typ` is a tuple, the last element of `fields` may be `Vararg`. In this case, it is
Expand Down
34 changes: 23 additions & 11 deletions base/compiler/typelimits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,9 @@ const issimpleenoughtupleelem = issimpleenoughtype
typea === typeb && return true
if typea isa PartialStruct
aty = widenconst(typea)
if length(typea.fields) > datatype_min_ninitialized(unwrap_unionall(aty))
return false # TODO more accuracy here?
end
for i = 1:length(typea.fields)
ai = unwrapva(typea.fields[i])
bi = fieldtype(aty, i)
Expand Down Expand Up @@ -572,34 +575,43 @@ end

# N.B. This can also be called with both typea::Const and typeb::Const to
# to recover PartialStruct from `Const`s with overlapping fields.
@nospecializeinfer function tmerge_partial_struct(lattice::PartialsLattice, @nospecialize(typea), @nospecialize(typeb))
@nospecializeinfer function tmerge_partial_struct(𝕃::PartialsLattice, @nospecialize(typea), @nospecialize(typeb))
aty = widenconst(typea)
bty = widenconst(typeb)
if aty === bty
# must have egal here, since we do not create PartialStruct for non-concrete types
typea_nfields = nfields_tfunc(lattice, typea)
typeb_nfields = nfields_tfunc(lattice, typeb)
typea_nfields = nfields_tfunc(𝕃, typea)
typeb_nfields = nfields_tfunc(𝕃, typeb)
isa(typea_nfields, Const) || return nothing
isa(typeb_nfields, Const) || return nothing
type_nfields = typea_nfields.val::Int
type_nfields === typeb_nfields.val::Int || return nothing
type_nfields == typeb_nfields.val::Int || return nothing
type_nfields == 0 && return nothing
if typea isa PartialStruct
if typeb isa PartialStruct
length(typea.fields) == length(typeb.fields) || return nothing
else
length(typea.fields) == type_nfields || return nothing
end
elseif typeb isa PartialStruct
length(typeb.fields) == type_nfields || return nothing
end
fields = Vector{Any}(undef, type_nfields)
anyrefine = false
for i = 1:type_nfields
ai = getfield_tfunc(lattice, typea, Const(i))
bi = getfield_tfunc(lattice, typeb, Const(i))
ai = getfield_tfunc(𝕃, typea, Const(i))
bi = getfield_tfunc(𝕃, typeb, Const(i))
# N.B.: We're assuming here that !isType(aty), because that case
# only arises when typea === typeb, which should have been caught
# before calling this.
ft = fieldtype(aty, i)
if is_lattice_equal(lattice, ai, bi) || is_lattice_equal(lattice, ai, ft)
if is_lattice_equal(𝕃, ai, bi) || is_lattice_equal(𝕃, ai, ft)
# Since ai===bi, the given type has no restrictions on complexity.
# and can be used to refine ft
tyi = ai
elseif is_lattice_equal(lattice, bi, ft)
elseif is_lattice_equal(𝕃, bi, ft)
tyi = bi
elseif (tyi′ = tmerge_field(lattice, ai, bi); tyi′ !== nothing)
elseif (tyi′ = tmerge_field(𝕃, ai, bi); tyi′ !== nothing)
# allow external lattice implementation to provide a custom field-merge strategy
tyi = tyi′
else
Expand All @@ -621,8 +633,8 @@ end
end
fields[i] = tyi
if !anyrefine
anyrefine = has_nontrivial_extended_info(lattice, tyi) || # extended information
(lattice, tyi, ft) # just a type-level information, but more precise than the declared type
anyrefine = has_nontrivial_extended_info(𝕃, tyi) || # extended information
(𝕃, tyi, ft) # just a type-level information, but more precise than the declared type
end
end
anyrefine && return PartialStruct(aty, fields)
Expand Down
75 changes: 47 additions & 28 deletions test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1538,7 +1538,7 @@ let nfields_tfunc(@nospecialize xs...) =
@test sizeof_nothrow(String)
@test !sizeof_nothrow(Type{String})
@test sizeof_tfunc(Type{Union{Int64, Int32}}) == Const(Core.sizeof(Union{Int64, Int32}))
let PT = Core.Compiler.PartialStruct(Tuple{Int64,UInt64}, Any[Const(10), UInt64])
let PT = Core.PartialStruct(Tuple{Int64,UInt64}, Any[Const(10), UInt64])
@test sizeof_tfunc(PT) === Const(16)
@test nfields_tfunc(PT) === Const(2)
@test sizeof_nothrow(PT)
Expand Down Expand Up @@ -4743,32 +4743,40 @@ end

# issue #43784
@testset "issue #43784" begin
init = Base.ImmutableDict{Any,Any}()
a = Const(init)
b = Core.PartialStruct(typeof(init), Any[Const(init), Any, Any])
c = Core.Compiler.tmerge(a, b)
@test (a, c)
@test (b, c)

init = Base.ImmutableDict{Number,Number}()
a = Const(init)
b = Core.Compiler.PartialStruct(typeof(init), Any[Const(init), Any, ComplexF64])
c = Core.Compiler.tmerge(a, b)
@test (a, c) && (b, c)
@test c === typeof(init)

a = Core.Compiler.PartialStruct(typeof(init), Any[Const(init), ComplexF64, ComplexF64])
c = Core.Compiler.tmerge(a, b)
@test (a, c) && (b, c)
@test c.fields[2] === Any # or Number
@test c.fields[3] === ComplexF64

b = Core.Compiler.PartialStruct(typeof(init), Any[Const(init), ComplexF32, Union{ComplexF32,ComplexF64}])
c = Core.Compiler.tmerge(a, b)
@test (a, c)
@test (b, c)
@test c.fields[2] === Complex
@test c.fields[3] === Complex
= Core.Compiler.partialorder(Core.Compiler.fallback_lattice)
= Core.Compiler.join(Core.Compiler.fallback_lattice)
Const, PartialStruct = Core.Const, Core.PartialStruct

let init = Base.ImmutableDict{Any,Any}()
a = Const(init)
b = PartialStruct(typeof(init), Any[Const(init), Any, Any])
c = a b
@test a c && b c
@test c === typeof(init)
end
let init = Base.ImmutableDict{Number,Number}()
a = Const(init)
b = PartialStruct(typeof(init), Any[Const(init), Number, ComplexF64])
c = a b
@test a c && b c
@test c === typeof(init)
end
let init = Base.ImmutableDict{Number,Number}()
a = PartialStruct(typeof(init), Any[Const(init), ComplexF64, ComplexF64])
b = PartialStruct(typeof(init), Any[Const(init), Number, ComplexF64])
c = a b
@test a c && b c
@test c.fields[2] === Number
@test c.fields[3] === ComplexF64
end
let init = Base.ImmutableDict{Number,Number}()
a = PartialStruct(typeof(init), Any[Const(init), ComplexF64, ComplexF64])
b = PartialStruct(typeof(init), Any[Const(init), ComplexF32, Union{ComplexF32,ComplexF64}])
c = a b
@test a c && b c
@test c.fields[2] === Complex
@test c.fields[3] === Complex
end

global const ginit43784 = Base.ImmutableDict{Any,Any}()
@test Base.return_types() do
Expand Down Expand Up @@ -5887,7 +5895,11 @@ end
end == Val{true}
@test Base.infer_return_type((Any,Any,)) do a, b
Val(isdefined(PartiallyInitialized1(a, b), :c))
end == Val{false}
end >: Val{false}
@test Base.infer_return_type((PartiallyInitialized1,)) do x
@assert isdefined(x, :a)
return Val(isdefined(x, :c))
end == Val
@test Base.infer_return_type((Any,Any,Any)) do a, b, c
Val(isdefined(PartiallyInitialized1(a, b, c), :c))
end == Val{true}
Expand Down Expand Up @@ -5949,6 +5961,13 @@ end |> Core.Compiler.is_nothrow
return x[]
end
end |> Core.Compiler.is_nothrow
@test Base.infer_effects((Any,Any); optimize=false) do a, c
x = PartiallyInitialized2(a)
x.c = c
if isdefined(x, :c)
return x.b
end
end |> !Core.Compiler.is_nothrow

# End to end test case for the partially initialized struct with `PartialStruct`
@noinline broadcast_noescape1(a) = (broadcast(identity, a); nothing)
Expand Down
6 changes: 3 additions & 3 deletions test/tuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ end
@test ntuple(identity, Val(n)) == ntuple(identity, n)
end

@test Core.Compiler.return_type(ntuple, Tuple{typeof(identity), Val}) == Tuple{Vararg{Int}}
@test Base.infer_return_type(ntuple, Tuple{typeof(identity), Val}) == Tuple{Vararg{Int}}
end

struct A_15703{N}
Expand Down Expand Up @@ -835,8 +835,8 @@ end
@test @inferred(Base.circshift(t3, 7)) == ('b', 'c', 'd', 'a')
@test @inferred(Base.circshift(t3, -1)) == ('b', 'c', 'd', 'a')
@test_throws MethodError circshift(t1, 'a')
@test Core.Compiler.return_type(circshift, Tuple{Tuple,Integer}) <: Tuple
@test Core.Compiler.return_type(circshift, Tuple{Tuple{Vararg{Any,10}},Integer}) <: Tuple{Vararg{Any,10}}
@test Base.infer_return_type(circshift, Tuple{Tuple,Integer}) <: Tuple
@test Base.infer_return_type(circshift, Tuple{Tuple{Vararg{Any,10}},Integer}) <: Tuple{Vararg{Any,10}}
for len 0:5
v = 1:len
t = Tuple(v)
Expand Down

0 comments on commit 032510c

Please sign in to comment.