@@ -55,17 +55,16 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
5555 # At this point we are guaranteed to end up throwing on this path,
5656 # which is all that's required for :consistent-cy. Of course, we don't
5757 # know anything else about this statement.
58- tristate_merge! (sv, Effects (; consistent= ALWAYS_TRUE, nonoverlayed) )
59- return CallMeta (Any, false )
58+ effects = Effects (; consistent= ALWAYS_TRUE, nonoverlayed)
59+ return CallMeta (Any, effects, false )
6060 end
6161
6262 argtypes = arginfo. argtypes
6363 matches = find_matching_methods (argtypes, atype, method_table (interp),
6464 InferenceParams (interp). MAX_UNION_SPLITTING, max_methods)
6565 if isa (matches, FailedMethodMatch)
6666 add_remark! (interp, sv, matches. reason)
67- tristate_merge! (sv, Effects ())
68- return CallMeta (Any, false )
67+ return CallMeta (Any, Effects (), false )
6968 end
7069
7170 (; valid_worlds, applicable, info) = matches
@@ -89,7 +88,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
8988
9089 # try pure-evaluation
9190 val = pure_eval_call (interp, f, applicable, arginfo, sv)
92- val != = nothing && return CallMeta (val, MethodResultPure (info)) # TODO : add some sort of edge(s)
91+ val != = nothing && return CallMeta (val, all_effects, MethodResultPure (info)) # TODO : add some sort of edge(s)
9392
9493 for i in 1 : napplicable
9594 match = applicable[i]:: MethodMatch
@@ -232,8 +231,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
232231 delete! (sv. pclimitations, caller)
233232 end
234233 end
235- tristate_merge! (sv, all_effects)
236- return CallMeta (rettype, info)
234+ return CallMeta (rettype, all_effects, info)
237235end
238236
239237struct FailedMethodMatch
@@ -1160,7 +1158,7 @@ function abstract_iteration(interp::AbstractInterpreter, @nospecialize(itft), @n
11601158 # WARNING: Changes to the iteration protocol must be reflected here,
11611159 # this is not just an optimization.
11621160 # TODO : this doesn't realize that Array, SimpleVector, Tuple, and NamedTuple do not use the iterate protocol
1163- stateordonet === Bottom && return Any[Bottom], AbstractIterationInfo (CallMeta[CallMeta (Bottom, info)])
1161+ stateordonet === Bottom && return Any[Bottom], AbstractIterationInfo (CallMeta[CallMeta (Bottom, call . effects, info)])
11641162 valtype = statetype = Bottom
11651163 ret = Any[]
11661164 calls = CallMeta[call]
@@ -1236,23 +1234,23 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::
12361234 max_methods:: Int = get_max_methods (sv. mod, interp))
12371235 itft = argtype_by_index (argtypes, 2 )
12381236 aft = argtype_by_index (argtypes, 3 )
1239- (itft === Bottom || aft === Bottom) && return CallMeta (Bottom, false )
1237+ (itft === Bottom || aft === Bottom) && return CallMeta (Bottom, EFFECTS_THROWS, false )
12401238 aargtypes = argtype_tail (argtypes, 4 )
12411239 aftw = widenconst (aft)
12421240 if ! isa (aft, Const) && ! isa (aft, PartialOpaque) && (! isType (aftw) || has_free_typevars (aftw))
12431241 if ! isconcretetype (aftw) || (aftw <: Builtin )
12441242 add_remark! (interp, sv, " Core._apply_iterate called on a function of a non-concrete type" )
1245- tristate_merge! (sv, Effects ())
12461243 # bail now, since it seems unlikely that abstract_call will be able to do any better after splitting
12471244 # this also ensures we don't call abstract_call_gf_by_type below on an IntrinsicFunction or Builtin
1248- return CallMeta (Any, false )
1245+ return CallMeta (Any, Effects (), false )
12491246 end
12501247 end
12511248 res = Union{}
12521249 nargs = length (aargtypes)
12531250 splitunions = 1 < unionsplitcost (aargtypes) <= InferenceParams (interp). MAX_APPLY_UNION_ENUM
12541251 ctypes = [Any[aft]]
12551252 infos = Vector{MaybeAbstractIterationInfo}[MaybeAbstractIterationInfo[]]
1253+ effects = EFFECTS_TOTAL
12561254 for i = 1 : nargs
12571255 ctypes´ = Vector{Any}[]
12581256 infos′ = Vector{MaybeAbstractIterationInfo}[]
@@ -1315,6 +1313,7 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::
13151313 call = abstract_call (interp, ArgInfo (nothing , ct), sv, max_methods)
13161314 push! (retinfos, ApplyCallInfo (call. info, arginfo))
13171315 res = tmerge (res, call. rt)
1316+ effects = tristate_merge (effects, call. effects)
13181317 if bail_out_apply (interp, res, sv)
13191318 if i != length (ctypes)
13201319 # No point carrying forward the info, we're not gonna inline it anyway
@@ -1325,7 +1324,7 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::
13251324 end
13261325 # TODO : Add a special info type to capture all the iteration info.
13271326 # For now, only propagate info if we don't also union-split the iteration
1328- return CallMeta (res, retinfo)
1327+ return CallMeta (res, effects, retinfo)
13291328end
13301329
13311330function argtype_by_index (argtypes:: Vector{Any} , i:: Int )
@@ -1506,21 +1505,21 @@ end
15061505function abstract_invoke (interp:: AbstractInterpreter , (; fargs, argtypes):: ArgInfo , sv:: InferenceState )
15071506 ft′ = argtype_by_index (argtypes, 2 )
15081507 ft = widenconst (ft′)
1509- ft === Bottom && return CallMeta (Bottom, false ), EFFECTS_THROWS
1508+ ft === Bottom && return CallMeta (Bottom, EFFECTS_THROWS, false )
15101509 (types, isexact, isconcrete, istype) = instanceof_tfunc (argtype_by_index (argtypes, 3 ))
1511- types === Bottom && return CallMeta (Bottom, false ), EFFECTS_THROWS
1512- isexact || return CallMeta (Any, false ), Effects ( )
1510+ types === Bottom && return CallMeta (Bottom, EFFECTS_THROWS, false )
1511+ isexact || return CallMeta (Any, Effects ( ), false )
15131512 argtype = argtypes_to_type (argtype_tail (argtypes, 4 ))
15141513 nargtype = typeintersect (types, argtype)
1515- nargtype === Bottom && return CallMeta (Bottom, false ), EFFECTS_THROWS
1516- nargtype isa DataType || return CallMeta (Any, false ), Effects ( ) # other cases are not implemented below
1517- isdispatchelem (ft) || return CallMeta (Any, false ), Effects ( ) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
1514+ nargtype === Bottom && return CallMeta (Bottom, EFFECTS_THROWS, false )
1515+ nargtype isa DataType || return CallMeta (Any, Effects ( ), false ) # other cases are not implemented below
1516+ isdispatchelem (ft) || return CallMeta (Any, Effects ( ), false ) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
15181517 ft = ft:: DataType
15191518 types = rewrap_unionall (Tuple{ft, unwrap_unionall (types). parameters... }, types):: Type
15201519 nargtype = Tuple{ft, nargtype. parameters... }
15211520 argtype = Tuple{ft, argtype. parameters... }
15221521 match, valid_worlds, overlayed = findsup (types, method_table (interp))
1523- match === nothing && return CallMeta (Any, false ), Effects ( )
1522+ match === nothing && return CallMeta (Any, Effects ( ), false )
15241523 update_valid_age! (sv, valid_worlds)
15251524 method = match. method
15261525 (ti, env:: SimpleVector ) = ccall (:jl_type_intersection_with_env , Any, (Any, Any), nargtype, method. sig):: SimpleVector
@@ -1547,7 +1546,7 @@ function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgIn
15471546 end
15481547 end
15491548 effects = Effects (effects; nonoverlayed= ! overlayed)
1550- return CallMeta (from_interprocedural! (rt, sv, arginfo, sig), InvokeCallInfo (match, const_result)), effects
1549+ return CallMeta (from_interprocedural! (rt, sv, arginfo, sig), effects, InvokeCallInfo (match, const_result))
15511550end
15521551
15531552function invoke_rewrite (xs:: Vector{Any} )
@@ -1568,37 +1567,30 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
15681567 if f === _apply_iterate
15691568 return abstract_apply (interp, argtypes, sv, max_methods)
15701569 elseif f === invoke
1571- call, effects = abstract_invoke (interp, arginfo, sv)
1572- tristate_merge! (sv, effects)
1573- return call
1570+ return abstract_invoke (interp, arginfo, sv)
15741571 elseif f === modifyfield!
1575- tristate_merge! (sv, Effects ()) # TODO
15761572 return abstract_modifyfield! (interp, argtypes, sv)
15771573 end
15781574 rt = abstract_call_builtin (interp, f, arginfo, sv, max_methods)
1579- tristate_merge! (sv, builtin_effects (f, argtypes, rt))
1580- return CallMeta (rt, false )
1575+ return CallMeta (rt, builtin_effects (f, argtypes, rt), false )
15811576 elseif isa (f, Core. OpaqueClosure)
15821577 # calling an OpaqueClosure about which we have no information returns no information
1583- tristate_merge! (sv, Effects ())
1584- return CallMeta (Any, false )
1578+ return CallMeta (Any, Effects (), false )
15851579 elseif f === Core. kwfunc
15861580 if la == 2
15871581 aty = argtypes[2 ]
15881582 if ! isvarargtype (aty)
15891583 ft = widenconst (aty)
15901584 if isa (ft, DataType) && isdefined (ft. name, :mt ) && isdefined (ft. name. mt, :kwsorter )
1591- return CallMeta (Const (ft. name. mt. kwsorter), MethodResultPure ())
1585+ return CallMeta (Const (ft. name. mt. kwsorter), EFFECTS_TOTAL, MethodResultPure ())
15921586 end
15931587 end
15941588 end
1595- tristate_merge! (sv, EFFECTS_UNKNOWN) # TODO
1596- return CallMeta (Any, false )
1589+ return CallMeta (Any, EFFECTS_UNKNOWN, false )
15971590 elseif f === TypeVar
15981591 # Manually look through the definition of TypeVar to
15991592 # make sure to be able to get `PartialTypeVar`s out.
1600- tristate_merge! (sv, EFFECTS_UNKNOWN) # TODO
1601- (la < 2 || la > 4 ) && return CallMeta (Union{}, false )
1593+ (la < 2 || la > 4 ) && return CallMeta (Union{}, EFFECTS_UNKNOWN, false )
16021594 n = argtypes[2 ]
16031595 ub_var = Const (Any)
16041596 lb_var = Const (Union{})
@@ -1608,36 +1600,33 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
16081600 elseif la == 3
16091601 ub_var = argtypes[3 ]
16101602 end
1611- return CallMeta (typevar_tfunc (n, lb_var, ub_var), false )
1603+ return CallMeta (typevar_tfunc (n, lb_var, ub_var), EFFECTS_UNKNOWN, false )
16121604 elseif f === UnionAll
1613- tristate_merge! (sv, EFFECTS_UNKNOWN) # TODO
1614- return CallMeta (abstract_call_unionall (argtypes), false )
1605+ return CallMeta (abstract_call_unionall (argtypes), EFFECTS_UNKNOWN, false )
16151606 elseif f === Tuple && la == 2
1616- tristate_merge! (sv, EFFECTS_UNKNOWN) # TODO
16171607 aty = argtypes[2 ]
16181608 ty = isvarargtype (aty) ? unwrapva (aty) : widenconst (aty)
16191609 if ! isconcretetype (ty)
1620- return CallMeta (Tuple, false )
1610+ return CallMeta (Tuple, EFFECTS_UNKNOWN, false )
16211611 end
16221612 elseif is_return_type (f)
1623- tristate_merge! (sv, EFFECTS_UNKNOWN) # TODO
16241613 return return_type_tfunc (interp, argtypes, sv)
16251614 elseif la == 2 && istopfunction (f, :! )
16261615 # handle Conditional propagation through !Bool
16271616 aty = argtypes[2 ]
16281617 if isa (aty, Conditional)
16291618 call = abstract_call_gf_by_type (interp, f, ArgInfo (fargs, Any[Const (f), Bool]), Tuple{typeof (f), Bool}, sv, max_methods) # make sure we've inferred `!(::Bool)`
1630- return CallMeta (Conditional (aty. var, aty. elsetype, aty. vtype), call. info)
1619+ return CallMeta (Conditional (aty. var, aty. elsetype, aty. vtype), call. effects, call . info)
16311620 end
16321621 elseif la == 3 && istopfunction (f, :!= = )
16331622 # mark !== as exactly a negated call to ===
16341623 rty = abstract_call_known (interp, (=== ), arginfo, sv, max_methods). rt
16351624 if isa (rty, Conditional)
1636- return CallMeta (Conditional (rty. var, rty. elsetype, rty. vtype), false ) # swap if-else
1625+ return CallMeta (Conditional (rty. var, rty. elsetype, rty. vtype), EFFECTS_TOTAL, false ) # swap if-else
16371626 elseif isa (rty, Const)
1638- return CallMeta (Const (rty. val === false ), MethodResultPure ())
1627+ return CallMeta (Const (rty. val === false ), EFFECTS_TOTAL, MethodResultPure ())
16391628 end
1640- return CallMeta (rty, false )
1629+ return CallMeta (rty, EFFECTS_TOTAL, false )
16411630 elseif la == 3 && istopfunction (f, :(> :))
16421631 # mark issupertype as a exact alias for issubtype
16431632 # swap T1 and T2 arguments and call <:
@@ -1647,28 +1636,28 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
16471636 fargs = nothing
16481637 end
16491638 argtypes = Any[typeof (< :), argtypes[3 ], argtypes[2 ]]
1650- return CallMeta (abstract_call_known (interp, < :, ArgInfo (fargs, argtypes), sv, max_methods). rt, false )
1639+ return CallMeta (abstract_call_known (interp, < :, ArgInfo (fargs, argtypes), sv, max_methods). rt, EFFECTS_TOTAL, false )
16511640 elseif la == 2 &&
16521641 (a2 = argtypes[2 ]; isa (a2, Const)) && (svecval = a2. val; isa (svecval, SimpleVector)) &&
16531642 istopfunction (f, :length )
16541643 # mark length(::SimpleVector) as @pure
1655- return CallMeta (Const (length (svecval)), MethodResultPure ())
1644+ return CallMeta (Const (length (svecval)), EFFECTS_TOTAL, MethodResultPure ())
16561645 elseif la == 3 &&
16571646 (a2 = argtypes[2 ]; isa (a2, Const)) && (svecval = a2. val; isa (svecval, SimpleVector)) &&
16581647 (a3 = argtypes[3 ]; isa (a3, Const)) && (idx = a3. val; isa (idx, Int)) &&
16591648 istopfunction (f, :getindex )
16601649 # mark getindex(::SimpleVector, i::Int) as @pure
16611650 if 1 <= idx <= length (svecval) && isassigned (svecval, idx)
1662- return CallMeta (Const (getindex (svecval, idx)), MethodResultPure ())
1651+ return CallMeta (Const (getindex (svecval, idx)), EFFECTS_TOTAL, MethodResultPure ())
16631652 end
16641653 elseif la == 2 && istopfunction (f, :typename )
1665- return CallMeta (typename_static (argtypes[2 ]), MethodResultPure ())
1654+ return CallMeta (typename_static (argtypes[2 ]), EFFECTS_TOTAL, MethodResultPure ())
16661655 elseif max_methods > 1 && istopfunction (f, :copyto! )
16671656 max_methods = 1
16681657 elseif la == 3 && istopfunction (f, :typejoin )
16691658 if is_all_const_arg (arginfo)
16701659 val = _pure_eval_call (f, arginfo)
1671- return CallMeta (val === nothing ? Type : val, MethodResultPure ())
1660+ return CallMeta (val === nothing ? Type : val, EFFECTS_TOTAL, MethodResultPure ())
16721661 end
16731662 end
16741663 atype = argtypes_to_type (argtypes)
@@ -1677,7 +1666,7 @@ end
16771666
16781667function abstract_call_opaque_closure (interp:: AbstractInterpreter , closure:: PartialOpaque , arginfo:: ArgInfo , sv:: InferenceState )
16791668 sig = argtypes_to_type (arginfo. argtypes)
1680- (; rt, edge) = result = abstract_call_method (interp, closure. source, sig, Core. svec (), false , sv)
1669+ (; rt, edge, edge_effects ) = result = abstract_call_method (interp, closure. source, sig, Core. svec (), false , sv)
16811670 edge != = nothing && add_backedge! (edge, sv)
16821671 tt = closure. typ
16831672 sigT = (unwrap_unionall (tt):: DataType ). parameters[1 ]
@@ -1693,7 +1682,7 @@ function abstract_call_opaque_closure(interp::AbstractInterpreter, closure::Part
16931682 end
16941683 end
16951684 info = OpaqueClosureCallInfo (match, const_result)
1696- return CallMeta (from_interprocedural! (rt, sv, arginfo, match. spec_types), info)
1685+ return CallMeta (from_interprocedural! (rt, sv, arginfo, match. spec_types), edge_effects, info)
16971686end
16981687
16991688function most_general_argtypes (closure:: PartialOpaque )
@@ -1715,18 +1704,30 @@ function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo,
17151704 if isa (ft, PartialOpaque)
17161705 newargtypes = copy (argtypes)
17171706 newargtypes[1 ] = ft. env
1718- tristate_merge! (sv, Effects ()) # TODO
1719- return abstract_call_opaque_closure (interp, ft, ArgInfo (arginfo. fargs, newargtypes), sv)
1707+ body_call = abstract_call_opaque_closure (interp, ft, ArgInfo (arginfo. fargs, newargtypes), sv)
1708+ # Analyze implicit type asserts on argument and return type
1709+ ftt = ft. typ
1710+ (at, rt) = unwrap_unionall (ftt). parameters
1711+ if isa (rt, TypeVar)
1712+ rt = rewrap_unionall (rt. lb, ftt)
1713+ else
1714+ rt = rewrap_unionall (rt, ftt)
1715+ end
1716+ nothrow = body_call. rt ⊑ rt
1717+ if nothrow
1718+ nothrow = tuple_tfunc (newargtypes[2 : end ]) ⊑ rewrap_unionall (at, ftt)
1719+ end
1720+ return CallMeta (body_call. rt, Effects (body_call. effects,
1721+ nothrow = nothrow ? TRISTATE_UNKNOWN : body_call. effects. nothrow),
1722+ body_call. info)
17201723 elseif (uft = unwrap_unionall (widenconst (ft)); isa (uft, DataType) && uft. name === typename (Core. OpaqueClosure))
1721- tristate_merge! (sv, Effects ()) # TODO
1722- return CallMeta (rewrap_unionall ((uft:: DataType ). parameters[2 ], widenconst (ft)), false )
1724+ return CallMeta (rewrap_unionall ((uft:: DataType ). parameters[2 ], widenconst (ft)), Effects (), false )
17231725 elseif f === nothing
17241726 # non-constant function, but the number of arguments is known
17251727 # and the ft is not a Builtin or IntrinsicFunction
17261728 if hasintersect (widenconst (ft), Union{Builtin, Core. OpaqueClosure})
1727- tristate_merge! (sv, Effects ())
17281729 add_remark! (interp, sv, " Could not identify method table for call" )
1729- return CallMeta (Any, false )
1730+ return CallMeta (Any, Effects (), false )
17301731 end
17311732 return abstract_call_gf_by_type (interp, nothing , arginfo, argtypes_to_type (argtypes), sv, max_methods)
17321733 end
@@ -1852,6 +1853,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
18521853 t = Bottom
18531854 else
18541855 callinfo = abstract_call (interp, ArgInfo (ea, argtypes), sv)
1856+ tristate_merge! (sv, callinfo. effects)
18551857 sv. stmt_info[sv. currpc] = callinfo. info
18561858 t = callinfo. rt
18571859 end
0 commit comments