Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve nothrow analysis of :new with missing sparam #46754

Merged
merged 1 commit into from
Sep 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions base/compiler/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -254,16 +254,31 @@ function stmt_effect_flags(lattice::AbstractLattice, @nospecialize(stmt), @nospe
nothrow = is_nothrow(effects)
return (consistent, effect_free & nothrow, nothrow)
elseif head === :new
typ = argextype(args[1], src)
atyp = argextype(args[1], src)
# `Expr(:new)` of unknown type could raise arbitrary TypeError.
typ, isexact = instanceof_tfunc(typ)
isexact || return (false, false, false)
isconcretedispatch(typ) || return (false, false, false)
typ, isexact = instanceof_tfunc(atyp)
if !isexact
atyp = unwrap_unionall(widenconst(atyp))
if isType(atyp) && isTypeDataType(atyp.parameters[1])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought at some point we had to deal with this check being insufficient and incomplete due to the existence of free-type-vars, for example if the user called:

julia> Val(Val.body);

which I thought used to be an issue for convert and Fix1 calls (particularly those implied by fieldtypes)

But perhaps we don't handle that case anyways, since that call segfaults, and this call poisons the dispatch cache permanently:

julia> Base.Fix1(Val.body, 1)
ERROR: UndefVarError: F not defined

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(see test/core.jl for TypeError("new", ...)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Types with missing sparams are not valid ::Types, because they error in subtyping. They can only dispatch as ::DataType. There's a few places in the code, where we aren't careful about it, but we just need to clean those up. I don't think :new with a type with a free tvar is legal either, but absent other bugs, I don't think this code allows that.

typ = atyp.parameters[1]
else
return (false, false, false)
end
isabstracttype(typ) && return (false, false, false)
else
isconcretedispatch(typ) || return (false, false, false)
end
typ = typ::DataType
fieldcount(typ) >= length(args) - 1 || return (false, false, false)
for fld_idx in 1:(length(args) - 1)
eT = argextype(args[fld_idx + 1], src)
fT = fieldtype(typ, fld_idx)
# Currently, we cannot represent any type equality constraints
# in the lattice, so if we see any type of type parameter,
# there is very little we can say about it
if !isexact && has_free_typevars(fT)
return (false, false, false)
end
eT ⊑ₒ fT || return (false, false, false)
end
return (false, true, true)
Expand Down
10 changes: 10 additions & 0 deletions test/compiler/effects.jl
Original file line number Diff line number Diff line change
Expand Up @@ -655,3 +655,13 @@ end # @testset "effects analysis on array ops" begin

# Test that builtin_effects handles vararg correctly
@test !Core.Compiler.is_nothrow(Core.Compiler.builtin_effects(Core.Compiler.fallback_lattice, Core.isdefined, Any[String, Vararg{Any}], Bool))

# Test that :new can be eliminated even if an sparam is unknown
struct SparamUnused{T}
x
SparamUnused(x::T) where {T} = new{T}(x)
end
mksparamunused(x) = (SparamUnused(x); nothing)
let src = code_typed1(mksparamunused, (Any,))
@test count(isnew, src.code) == 0
end