Skip to content

Commit

Permalink
Improve nothrow analysis of :new with missing sparam (#46754)
Browse files Browse the repository at this point in the history
Similar to #46693, but for :new, rather than getfield.
Unfortunately, this is somewhat limited as we don't really
have the ability to encode type equality constraints in the
lattice. In particular, it would be nice to analyze:

```
struct Foo{T}
    x::T
    Foo(x::T) where {T} = new{T}(x)
end
```

and be able to prove this nothrow. If it's really
important, we could probably pattern match it, but
for the moment, this is not easy to do. Nevertheless,
we can do something about the similar, but simpler pattern

```
struct Foo{T}
    x
    Foo(x::T) where {T} = new{T}(x)
end
```

which is what this PR does.
  • Loading branch information
Keno authored Sep 15, 2022
1 parent e758982 commit 94c3a15
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 4 deletions.
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])
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

0 comments on commit 94c3a15

Please sign in to comment.