Repository: JuliaLang/julia
File: Compiler/src/abstractinterpretation.jl (Julia)

Code before:
    Future{Any}(call, interp, sv) do call, _, sv
        # this only is needed for the side-effect, sequenced before any task tries to consume the return value,
        # which this will do even without returning this Future
        sv.stmt_info[sv.currpc] = call.info
        nothing
    end
    return call
end

function abstract_eval_call(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
                            sv::AbsIntState)
    ea = e.args
    argtypes = collect_argtypes(interp, ea, sstate, sv)
    if argtypes === nothing
        return Future(RTEffects(Bottom, Any, Effects()))
    end
    arginfo = ArgInfo(ea, argtypes)
    call = abstract_call(interp, arginfo, sstate, sv)::Future
    return Future{RTEffects}(call, interp, sv) do call, _, _
        (; rt, exct, effects, refinements) = call
        return RTEffects(rt, exct, effects, refinements)
    end
end

function is_field_pointerfree(dt::DataType, fidx::Int)
    dt.layout == C_NULL && return false
    DataTypeFieldDesc(dt)[fidx].isptr && return false
    ft = fieldtype(dt, fidx)
    return ft isa DataType && datatype_pointerfree(ft)
end

function abstract_eval_new(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
                           sv::AbsIntState)
    𝕃ᵢ = typeinf_lattice(interp)
    rt, _... = instanceof_tfunc(abstract_eval_value(interp, e.args[1], sstate, sv), true)
    ut = unwrap_unionall(rt)
    exct = Union{ErrorException,TypeError}
    if isa(ut, DataType) && !isabstracttype(ut)
        ismutable = ismutabletype(ut)
        fcount = datatype_fieldcount(ut)
        nargs = length(e.args) - 1
        has_any_uninitialized = fcount === nothing || (fcount > nargs &&
            any(i::Int->is_field_pointerfree(ut, i), (nargs+1):fcount))
        if has_any_uninitialized
            # allocation with undefined field is inconsistent always
            consistent = ALWAYS_FALSE
        elseif ismutable
            # mutable allocation isn't `:consistent`, but we still have a chance that
            # return type information later refines the `:consistent`-cy of the method
            consistent = CONSISTENT_IF_NOTRETURNED
        else

Review comment (suggestion):
I would add a type-assert to avoid invalidations, see https://github.com/JuliaLang/julia/pull/59886:
```suggestion
    dt.layout::Ptr{Cvoid} == C_NULL && return false
```

Code after:
    Future{Any}(call, interp, sv) do call, _, sv
        # this only is needed for the side-effect, sequenced before any task tries to consume the return value,
        # which this will do even without returning this Future
        sv.stmt_info[sv.currpc] = call.info
        nothing
    end
    return call
end

function abstract_eval_call(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
                            sv::AbsIntState)
    ea = e.args
    argtypes = collect_argtypes(interp, ea, sstate, sv)
    if argtypes === nothing
        return Future(RTEffects(Bottom, Any, Effects()))
    end
    arginfo = ArgInfo(ea, argtypes)
    call = abstract_call(interp, arginfo, sstate, sv)::Future
    return Future{RTEffects}(call, interp, sv) do call, _, _
        (; rt, exct, effects, refinements) = call
        return RTEffects(rt, exct, effects, refinements)
    end
end

function is_field_pointerfree(dt::DataType, fidx::Int)
    dt.layout::Ptr{Cvoid} == C_NULL && return false
    DataTypeFieldDesc(dt)[fidx].isptr && return false
    ft = fieldtype(dt, fidx)
    return ft isa DataType && datatype_pointerfree(ft)
end

function abstract_eval_new(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
                           sv::AbsIntState)
    𝕃ᵢ = typeinf_lattice(interp)
    rt, _... = instanceof_tfunc(abstract_eval_value(interp, e.args[1], sstate, sv), true)
    ut = unwrap_unionall(rt)
    exct = Union{ErrorException,TypeError}
    if isa(ut, DataType) && !isabstracttype(ut)
        ismutable = ismutabletype(ut)
        fcount = datatype_fieldcount(ut)
        nargs = length(e.args) - 1
        has_any_uninitialized = fcount === nothing || (fcount > nargs &&
            any(i::Int->is_field_pointerfree(ut, i), (nargs+1):fcount))
        if has_any_uninitialized
            # allocation with undefined field is inconsistent always
            consistent = ALWAYS_FALSE
        elseif ismutable
            # mutable allocation isn't `:consistent`, but we still have a chance that
            # return type information later refines the `:consistent`-cy of the method
            consistent = CONSISTENT_IF_NOTRETURNED
        else