@@ -67,7 +67,7 @@ add_tfunc(throw, 1, 1, (@nospecialize(x)) -> Bottom, 0)
67
67
# if istype is true, the actual runtime value will definitely be a type (e.g. this is false for Union{Type{Int}, Int})
68
68
function instanceof_tfunc (@nospecialize (t))
69
69
if isa (t, Const)
70
- if isa (t. val, Type)
70
+ if isa (t. val, Type) && valid_as_lattice (t . val)
71
71
return t. val, true , isconcretetype (t. val), true
72
72
end
73
73
return Bottom, true , false , false # runtime throws on non-Type
@@ -79,6 +79,7 @@ function instanceof_tfunc(@nospecialize(t))
79
79
return Bottom, true , false , false # literal Bottom or non-Type
80
80
elseif isType (t)
81
81
tp = t. parameters[1 ]
82
+ valid_as_lattice (tp) || return Bottom, true , false , false # runtime unreachable / throws on non-Type
82
83
return tp, ! has_free_typevars (tp), isconcretetype (tp), true
83
84
elseif isa (t, UnionAll)
84
85
t′ = unwrap_unionall (t)
@@ -473,7 +474,8 @@ function pointer_eltype(@nospecialize(ptr))
473
474
unw = unwrap_unionall (a)
474
475
if isa (unw, DataType) && unw. name === Ptr. body. name
475
476
T = unw. parameters[1 ]
476
- T isa Type && return rewrap_unionall (T, a)
477
+ valid_as_lattice (T) || return Bottom
478
+ return rewrap_unionall (T, a)
477
479
end
478
480
end
479
481
return Any
@@ -486,7 +488,8 @@ function atomic_pointermodify_tfunc(ptr, op, v, order)
486
488
if isa (unw, DataType) && unw. name === Ptr. body. name
487
489
T = unw. parameters[1 ]
488
490
# note: we could sometimes refine this to a PartialStruct if we analyzed `op(T, T)::T`
489
- T isa Type && return rewrap_unionall (Pair{T, T}, a)
491
+ valid_as_lattice (T) || return Bottom
492
+ return rewrap_unionall (Pair{T, T}, a)
490
493
end
491
494
end
492
495
return Pair
@@ -498,7 +501,8 @@ function atomic_pointerreplace_tfunc(ptr, x, v, success_order, failure_order)
498
501
unw = unwrap_unionall (a)
499
502
if isa (unw, DataType) && unw. name === Ptr. body. name
500
503
T = unw. parameters[1 ]
501
- T isa Type && return rewrap_unionall (ccall (:jl_apply_cmpswap_type , Any, (Any,), T), a)
504
+ valid_as_lattice (T) || return Bottom
505
+ return rewrap_unionall (ccall (:jl_apply_cmpswap_type , Any, (Any,), T), a)
502
506
end
503
507
end
504
508
return ccall (:jl_apply_cmpswap_type , Any, (Any,), T) where T
@@ -754,8 +758,8 @@ function getfield_nothrow(@nospecialize(s00), @nospecialize(name), boundscheck::
754
758
s0 = widenconst (s00)
755
759
s = unwrap_unionall (s0)
756
760
if isa (s, Union)
757
- return getfield_nothrow (rewrap (s. a, s00), name, boundscheck) &&
758
- getfield_nothrow (rewrap (s. b, s00), name, boundscheck)
761
+ return getfield_nothrow (rewrap_unionall (s. a, s00), name, boundscheck) &&
762
+ getfield_nothrow (rewrap_unionall (s. b, s00), name, boundscheck)
759
763
elseif isa (s, DataType)
760
764
# Can't say anything about abstract types
761
765
isabstracttype (s) && return false
@@ -782,8 +786,8 @@ getfield_tfunc(s00, name, order, boundscheck) = (@nospecialize; getfield_tfunc(s
782
786
function getfield_tfunc (@nospecialize (s00), @nospecialize (name))
783
787
s = unwrap_unionall (s00)
784
788
if isa (s, Union)
785
- return tmerge (getfield_tfunc (rewrap (s. a,s00), name),
786
- getfield_tfunc (rewrap (s. b,s00), name))
789
+ return tmerge (getfield_tfunc (rewrap_unionall (s. a, s00), name),
790
+ getfield_tfunc (rewrap_unionall (s. b, s00), name))
787
791
elseif isa (s, Conditional)
788
792
return Bottom # Bool has no fields
789
793
elseif isa (s, Const) || isconstType (s)
@@ -857,9 +861,6 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name))
857
861
end
858
862
return Any
859
863
end
860
- # If no value has this type, then this statement should be unreachable.
861
- # Bail quickly now.
862
- has_concrete_subtype (s) || return Union{}
863
864
if s. name === _NAMEDTUPLE_NAME && ! isconcretetype (s)
864
865
if isa (name, Const) && isa (name. val, Symbol)
865
866
if isa (s. parameters[1 ], Tuple)
@@ -878,7 +879,9 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name))
878
879
return getfield_tfunc (_ts, name)
879
880
end
880
881
ftypes = datatype_fieldtypes (s)
881
- if isempty (ftypes)
882
+ # If no value has this type, then this statement should be unreachable.
883
+ # Bail quickly now.
884
+ if ! has_concrete_subtype (s) || isempty (ftypes)
882
885
return Bottom
883
886
end
884
887
if isa (name, Conditional)
@@ -1072,8 +1075,8 @@ function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
1072
1075
1073
1076
su = unwrap_unionall (s0)
1074
1077
if isa (su, Union)
1075
- return tmerge (fieldtype_tfunc (rewrap (su. a, s0), name),
1076
- fieldtype_tfunc (rewrap (su. b, s0), name))
1078
+ return tmerge (fieldtype_tfunc (rewrap_unionall (su. a, s0), name),
1079
+ fieldtype_tfunc (rewrap_unionall (su. b, s0), name))
1077
1080
end
1078
1081
1079
1082
s, exact = instanceof_tfunc (s0)
@@ -1085,8 +1088,8 @@ function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name))
1085
1088
exact = exact && ! has_free_typevars (s)
1086
1089
u = unwrap_unionall (s)
1087
1090
if isa (u, Union)
1088
- ta0 = _fieldtype_tfunc (rewrap (u. a, s), exact, name)
1089
- tb0 = _fieldtype_tfunc (rewrap (u. b, s), exact, name)
1091
+ ta0 = _fieldtype_tfunc (rewrap_unionall (u. a, s), exact, name)
1092
+ tb0 = _fieldtype_tfunc (rewrap_unionall (u. b, s), exact, name)
1090
1093
ta0 ⊑ tb0 && return tb0
1091
1094
tb0 ⊑ ta0 && return ta0
1092
1095
ta, exacta, _, istypea = instanceof_tfunc (ta0)
@@ -1296,7 +1299,11 @@ function apply_type_tfunc(@nospecialize(headtypetype), @nospecialize args...)
1296
1299
end
1297
1300
end
1298
1301
end
1299
- largs == 1 && return isa (args[1 ], Type) ? typeintersect (args[1 ], Type) : Type
1302
+ if largs == 1 # Union{T} --> T
1303
+ u1 = typeintersect (widenconst (args[1 ]), Type)
1304
+ valid_as_lattice (u1) || return Bottom
1305
+ return u1
1306
+ end
1300
1307
hasnonType && return Type
1301
1308
ty = Union{}
1302
1309
allconst = true
@@ -1471,21 +1478,26 @@ end
1471
1478
1472
1479
function arrayref_tfunc (@nospecialize (boundscheck), @nospecialize (a), @nospecialize i... )
1473
1480
a = widenconst (a)
1474
- if a <: Array
1475
- if isa (a, DataType) && isa (a. parameters[1 ], Type)
1476
- return a. parameters[1 ]
1477
- elseif isa (a, UnionAll) && ! has_free_typevars (a)
1478
- unw = unwrap_unionall (a)
1479
- if isa (unw, DataType)
1480
- return rewrap_unionall (unw. parameters[1 ], a)
1481
- end
1481
+ if ! has_free_typevars (a) && a <: Array
1482
+ a0 = a
1483
+ if isa (a, UnionAll)
1484
+ a = unwrap_unionall (a0)
1485
+ end
1486
+ if isa (a, DataType)
1487
+ T = a. parameters[1 ]
1488
+ valid_as_lattice (T) || return Bottom
1489
+ return rewrap_unionall (T, a0)
1482
1490
end
1483
1491
end
1484
1492
return Any
1485
1493
end
1486
1494
add_tfunc (arrayref, 3 , INT_INF, arrayref_tfunc, 20 )
1487
1495
add_tfunc (const_arrayref, 3 , INT_INF, arrayref_tfunc, 20 )
1488
- add_tfunc (arrayset, 4 , INT_INF, (@nospecialize (boundscheck), @nospecialize (a), @nospecialize (v), @nospecialize i... )-> a, 20 )
1496
+ function arrayset_tfunc (@nospecialize (boundscheck), @nospecialize (a), @nospecialize (v), @nospecialize i... )
1497
+ # TODO : we could check that the type-intersect of arrayref_tfunc and v is non-empty or always throws
1498
+ return a
1499
+ end
1500
+ add_tfunc (arrayset, 4 , INT_INF, arrayset_tfunc, 20 )
1489
1501
1490
1502
function _opaque_closure_tfunc (@nospecialize (arg), @nospecialize (isva),
1491
1503
@nospecialize (lb), @nospecialize (ub), @nospecialize (source), env:: Vector{Any} ,
@@ -1508,6 +1520,7 @@ function _opaque_closure_tfunc(@nospecialize(arg), @nospecialize(isva),
1508
1520
return PartialOpaque (t, tuple_tfunc (env), isva. val, linfo, source. val)
1509
1521
end
1510
1522
1523
+ # whether getindex for the elements can potentially throw UndefRef
1511
1524
function array_type_undefable (@nospecialize (a))
1512
1525
if isa (a, Union)
1513
1526
return array_type_undefable (a. a) || array_type_undefable (a. b)
@@ -1550,7 +1563,7 @@ function _builtin_nothrow(@nospecialize(f), argtypes::Array{Any,1}, @nospecializ
1550
1563
# Check that we can determine the element type
1551
1564
(isa (a, DataType) && isa (a. parameters[1 ], Type)) || return false
1552
1565
# Check that the element type is compatible with the element we're assigning
1553
- (argtypes[3 ] ⊑ a. parameters[1 ]:: Type ) || return false
1566
+ (argtypes[3 ] ⊑ a. parameters[1 ]) || return false
1554
1567
return true
1555
1568
elseif f === arrayref || f === const_arrayref
1556
1569
return array_builtin_common_nothrow (argtypes, 3 )
0 commit comments