Skip to content

Commit

Permalink
attempt to refine return type when it could be improved via PartialTuple
Browse files Browse the repository at this point in the history
  • Loading branch information
jrevels committed Dec 17, 2018
1 parent b167bc2 commit f95d2e3
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 9 deletions.
8 changes: 4 additions & 4 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ function abstract_call_gf_by_type(@nospecialize(f), argtypes::Vector{Any}, @nosp
# if there's a possibility we could constant-propagate a better result
# (hopefully without doing too much work), try to do that now
# TODO: it feels like this could be better integrated into abstract_call_method / typeinf_edge
const_rettype = abstract_call_method_with_const_args(f, argtypes, applicable[nonbot]::SimpleVector, sv)
const_rettype = abstract_call_method_with_const_args(rettype, f, argtypes, applicable[nonbot]::SimpleVector, sv)
if const_rettype rettype
# use the better result, if it's a refinement of rettype
rettype = const_rettype
Expand Down Expand Up @@ -142,7 +142,7 @@ function abstract_call_gf_by_type(@nospecialize(f), argtypes::Vector{Any}, @nosp
return rettype
end

function abstract_call_method_with_const_args(@nospecialize(f), argtypes::Vector{Any}, match::SimpleVector, sv::InferenceState)
function abstract_call_method_with_const_args(@nospecialize(rettype), @nospecialize(f), argtypes::Vector{Any}, match::SimpleVector, sv::InferenceState)
method = match[3]::Method
nargs::Int = method.nargs
method.isva && (nargs -= 1)
Expand All @@ -159,7 +159,7 @@ function abstract_call_method_with_const_args(@nospecialize(f), argtypes::Vector
end
end
end
haveconst || return Any
haveconst || improvable_via_constant_propagation(rettype) || return Any
sig = match[1]
sparams = match[2]::SimpleVector
code = code_for_method(method, sig, sparams, sv.params.world)
Expand Down Expand Up @@ -1060,7 +1060,7 @@ function typeinf_local(frame::InferenceState)
elseif hd === :return
pc´ = n + 1
rt = widenconditional(abstract_eval(stmt.args[1], s[pc], frame))
if !isa(rt, Const) && !isa(rt, Type) && (!isa(rt, PartialTuple) || frame.cached)
if !isa(rt, Const) && !isa(rt, Type) && !isa(rt, PartialTuple)
# only propagate information we know we can store
# and is valid inter-procedurally
rt = widenconst(rt)
Expand Down
6 changes: 3 additions & 3 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ function analyze_method!(idx::Int, @nospecialize(f), @nospecialize(ft), @nospeci
return ConstantCase(quoted(linfo.inferred_const), method, Any[methsp...], metharg)
end

isconst, inferred = find_inferred(linfo, atypes, sv)
isconst, inferred = find_inferred(linfo, atypes, sv, stmttyp)
if isconst
return ConstantCase(inferred, method, Any[methsp...], metharg)
end
Expand Down Expand Up @@ -1152,7 +1152,7 @@ function ssa_substitute_op!(@nospecialize(val), arg_replacements::Vector{Any},
return urs[]
end

function find_inferred(linfo::MethodInstance, @nospecialize(atypes), sv::OptimizationState)
function find_inferred(linfo::MethodInstance, @nospecialize(atypes), sv::OptimizationState, @nospecialize(rettype))
# see if the method has a InferenceResult in the current cache
# or an existing inferred code info store in `.inferred`
haveconst = false
Expand All @@ -1163,7 +1163,7 @@ function find_inferred(linfo::MethodInstance, @nospecialize(atypes), sv::Optimiz
break
end
end
if haveconst
if haveconst || improvable_via_constant_propagation(rettype)
inf_result = cache_lookup(linfo, atypes, sv.params.cache) # Union{Nothing, InferenceResult}
else
inf_result = nothing
Expand Down
8 changes: 6 additions & 2 deletions base/compiler/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -495,15 +495,19 @@ function typeinf_edge(method::Method, @nospecialize(atypes), sparams::SimpleVect
frame.parent = caller
end
typeinf(frame)
return frame.bestguess, frame.inferred ? frame.linfo : nothing
return widenconst_bestguess(frame.bestguess), frame.inferred ? frame.linfo : nothing
elseif frame === true
# unresolvable cycle
return Any, nothing
end
frame = frame::InferenceState
return frame.bestguess, nothing
return widenconst_bestguess(frame.bestguess), nothing
end

function widenconst_bestguess(bestguess)
!isa(bestguess, Const) && !isa(bestguess, Type) && return widenconst(bestguess)
return bestguess
end

#### entry points for inferring a MethodInstance given a type signature ####

Expand Down
9 changes: 9 additions & 0 deletions base/compiler/typeutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,12 @@ function unioncomplexity(t::DataType)
end
unioncomplexity(u::UnionAll) = max(unioncomplexity(u.body), unioncomplexity(u.var.ub))
unioncomplexity(@nospecialize(x)) = 0

function improvable_via_constant_propagation(@nospecialize(t))
if isconcretetype(t) && t <: Tuple
for p in t.parameters
p === DataType && return true
end
end
return false
end
12 changes: 12 additions & 0 deletions test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2172,3 +2172,15 @@ f30394(foo::T1, ::Type{T2}) where {T2, T1 <: T2} = foo
f30394(foo, T2) = f30394(foo.foo_inner, T2)

@test Base.return_types(f30394, (Foo30394_2, Type{Base30394})) == Any[Base30394]

# PR #30385

g30385(args...) = h30385(args...)
h30385(f, args...) = f(args...)
f30385(T, y) = g30385(getfield, g30385(tuple, T, y), 1)
k30385(::Type{AbstractFloat}) = 1
k30385(x) = "dummy"
j30385(T, y) = k30385(f30385(T, y))

@test @inferred(j30385(AbstractFloat, 1)) == 1
@test @inferred(j30385(:dummy, 1)) == "dummy"

0 comments on commit f95d2e3

Please sign in to comment.