From a3a91829227efd438e30e83215bdf7a04bc5869d Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Fri, 3 Sep 2021 06:41:29 +0900 Subject: [PATCH] inference: fix #42090, make sure not to wrap `Conditional` in `PartialStruct` (#42091) (cherry picked from commit 03e7b23033aa8d05233893ebdb73c3f081cf0ffe) --- base/compiler/abstractinterpretation.jl | 2 +- test/compiler/inference.jl | 33 +++++++++++++++++++++---- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index bb6702dede1db..47758f70a8715 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -1476,7 +1476,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), anyconst = false allconst = true for i = 2:length(e.args) - at = abstract_eval_value(interp, e.args[i], vtypes, sv) + at = widenconditional(abstract_eval_value(interp, e.args[i], vtypes, sv)) if !anyconst anyconst = has_nontrivial_const_info(at) end diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 567df71a7b16a..aa33f4a112aac 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -1828,16 +1828,39 @@ end return c, d # ::Tuple{Int,Int} end == Any[Tuple{Int,Int}] - # shouldn't use the old constraint when the subject of condition has changed + # should invalidate old constraint when the subject of condition has changed @test Base.return_types((Union{Nothing,Int},)) do a - b = a === nothing - c = b ? 0 : a # c::Int + cond = a === nothing + r1 = cond ? 0 : a # r1::Int a = 0 - d = b ? a : 1 # d::Int, not d::Union{Nothing,Int} - return c, d # ::Tuple{Int,Int} + r2 = cond ? a : 1 # r2::Int, not r2::Union{Nothing,Int} + return r1, r2 # ::Tuple{Int,Int} end == Any[Tuple{Int,Int}] end +# https://github.com/JuliaLang/julia/issues/42090#issuecomment-911824851 +# `PartialStruct` shoudln't wrap `Conditional` +let M = Module() + @eval M begin + struct BePartialStruct + val::Int + cond + end + end + + rt = @eval M begin + Base.return_types((Union{Nothing,Int},)) do a + cond = a === nothing + obj = $(Expr(:new, M.BePartialStruct, 42, :cond)) + r1 = getfield(obj, :cond) ? 0 : a # r1::Union{Nothing,Int}, not r1::Int (because PartialStruct doesn't wrap Conditional) + a = $(gensym(:anyvar))::Any + r2 = getfield(obj, :cond) ? a : nothing # r2::Any, not r2::Const(nothing) (we don't need to worry about constrait invalidation here) + return r1, r2 # ::Tuple{Union{Nothing,Int},Any} + end |> only + end + @test rt == Tuple{Union{Nothing,Int},Any} +end + @testset "conditional constraint propagation from non-`Conditional` object" begin @test Base.return_types((Bool,)) do b if b