Skip to content

Commit

Permalink
inference: propagate partially initialized mutable structs more
Browse files Browse the repository at this point in the history
Following up #55297.
A mutable struct can have undefined fields in a non-contiguous manner,
but `PartialStruct` cannot model such a state. So in #55297
`PartialStruct` was used to represent only the mutable objects where the
field following the minimum initialized fields is also defined.

As a follow-up for the PR, this commit implements a minor improvement
that, in cases when the mutable object is already represented as a
`PartialStruct`, allows inference to add one more `isdefined`-field
information on top of those implied by its `fields`.

```julia
mutable struct PartiallyInitialized2
    a; b; c
    PartiallyInitialized2(a) = (@nospecialize; new(a))
    PartiallyInitialized2(a, b) = (@nospecialize; new(a, b))
    PartiallyInitialized2(a, b, c) = (@nospecialize; new(a, b, c))
end

@test Base.infer_effects((PartiallyInitialized2,); optimize=false) do x
    if isdefined(x, :b)
        if isdefined(x, :c)
            return x.c
        end
        return x.b
    end
    return nothing
end |> Core.Compiler.is_nothrow
```
  • Loading branch information
aviatesk committed Aug 20, 2024
1 parent 9650510 commit 4e0c2cf
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 1 deletion.
11 changes: 10 additions & 1 deletion base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2057,7 +2057,16 @@ function form_partially_defined_struct(@nospecialize(obj), @nospecialize(name))
fldidx === nothing && return nothing
nminfld = datatype_min_ninitialized(objt)
if ismutabletype(objt)
fldidx == nminfld+1 || return nothing
if fldidx nminfld+1
# A mutable struct can have gutshot undefined fields, but `PartialStruct` cannot
# model such a state. So here `PartialStruct` can be used to represent only the
# objects where the field following the minimum initialized fields is also defined.
if !(obj isa PartialStruct && fldidx == length(obj.fields)+1)
# if it is already represented as a `PartialStruct`, we can add one more
# `isdefined`-field information on top of those implied by its `fields`
return nothing
end
end
else
fldidx > nminfld || return nothing
end
Expand Down
9 changes: 9 additions & 0 deletions test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6033,6 +6033,15 @@ end |> Core.Compiler.is_nothrow
return x.b
end
end |> !Core.Compiler.is_nothrow
@test Base.infer_effects((PartiallyInitialized2,); optimize=false) do x
if isdefined(x, :b)
if isdefined(x, :c)
return x.c
end
return x.b
end
return nothing
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

0 comments on commit 4e0c2cf

Please sign in to comment.