@@ -2057,9 +2057,9 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
2057
2057
/** Returns last check's debug mode, if explicitly enabled. */
2058
2058
def lastTrace (): String = " "
2059
2059
2060
- /** Do `tp1` and `tp2` share a non-null inhabitant ?
2060
+ /** Are `tp1` and `tp2` disjoint types ?
2061
2061
*
2062
- * `false ` implies that we found a proof; uncertainty default to `true `.
2062
+ * `true ` implies that we found a proof; uncertainty default to `false `.
2063
2063
*
2064
2064
* Proofs rely on the following properties of Scala types:
2065
2065
*
@@ -2068,8 +2068,8 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
2068
2068
* 3. ConstantTypes with distinc values are non intersecting
2069
2069
* 4. There is no value of type Nothing
2070
2070
*/
2071
- def intersecting (tp1 : Type , tp2 : Type )(implicit ctx : Context ): Boolean = {
2072
- // println(s"intersecting (${tp1.show}, ${tp2.show})")
2071
+ def disjoint (tp1 : Type , tp2 : Type )(implicit ctx : Context ): Boolean = {
2072
+ // println(s"disjoint (${tp1.show}, ${tp2.show})")
2073
2073
/** Can we enumerate all instantiations of this type? */
2074
2074
def isClosedSum (tp : Symbol ): Boolean =
2075
2075
tp.is(Sealed ) && tp.is(AbstractOrTrait ) && ! tp.hasAnonymousChild
@@ -2082,46 +2082,35 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
2082
2082
sym.children.map(x => ctx.refineUsingParent(tp, x)).filter(_.exists)
2083
2083
2084
2084
(tp1.dealias, tp2.dealias) match {
2085
+ case (tp1 : TypeRef , tp2 : TypeRef ) if tp1.symbol == defn.SingletonClass || tp2.symbol == defn.SingletonClass =>
2086
+ false
2085
2087
case (tp1 : ConstantType , tp2 : ConstantType ) =>
2086
- tp1 = = tp2
2088
+ tp1 ! = tp2
2087
2089
case (tp1 : TypeRef , tp2 : TypeRef ) if tp1.symbol.isClass && tp2.symbol.isClass =>
2088
2090
val cls1 = tp1.classSymbol
2089
2091
val cls2 = tp2.classSymbol
2090
2092
if (cls1.derivesFrom(cls2) || cls2.derivesFrom(cls1)) {
2091
- true
2093
+ false
2092
2094
} else {
2093
2095
if (cls1.is(Final ) || cls2.is(Final ))
2094
2096
// One of these types is final and they are not mutually
2095
2097
// subtype, so they must be unrelated.
2096
- false
2098
+ true
2097
2099
else if (! cls2.is(Trait ) && ! cls1.is(Trait ))
2098
2100
// Both of these types are classes and they are not mutually
2099
2101
// subtype, so they must be unrelated by single inheritance
2100
2102
// of classes.
2101
- false
2103
+ true
2102
2104
else if (isClosedSum(cls1))
2103
- decompose(cls1, tp1).exists (x => intersecting (x, tp2))
2105
+ decompose(cls1, tp1).forall (x => disjoint (x, tp2))
2104
2106
else if (isClosedSum(cls2))
2105
- decompose(cls2, tp2).exists (x => intersecting (x, tp1))
2107
+ decompose(cls2, tp2).forall (x => disjoint (x, tp1))
2106
2108
else
2107
- true
2109
+ false
2108
2110
}
2109
2111
case (AppliedType (tycon1, args1), AppliedType (tycon2, args2)) if tycon1 == tycon2 =>
2110
- // Unboxed xs.zip(ys).zip(zs).forall { case ((a, b), c) => f(a, b, c) }
2111
- def zip_zip_forall [A , B , C ](xs : List [A ], ys : List [B ], zs : List [C ])(f : (A , B , C ) => Boolean ): Boolean = {
2112
- xs match {
2113
- case x :: xs => ys match {
2114
- case y :: ys => zs match {
2115
- case z :: zs => f(x, y, z) && zip_zip_forall(xs, ys, zs)(f)
2116
- case _ => true
2117
- }
2118
- case _ => true
2119
- }
2120
- case _ => true
2121
- }
2122
- }
2123
- def covariantIntersecting (tp1 : Type , tp2 : Type , tparam : TypeParamInfo ): Boolean = {
2124
- intersecting(tp1, tp2) || {
2112
+ def covariantDisjoint (tp1 : Type , tp2 : Type , tparam : TypeParamInfo ): Boolean = {
2113
+ disjoint(tp1, tp2) && {
2125
2114
// We still need to proof that `Nothing` is not a valid
2126
2115
// instantiation of this type parameter. We have two ways
2127
2116
// to get to that conclusion:
@@ -2139,24 +2128,24 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
2139
2128
case _ =>
2140
2129
false
2141
2130
}
2142
- lowerBoundedByNothing && ! typeUsedAsField
2131
+ ! lowerBoundedByNothing || typeUsedAsField
2143
2132
}
2144
2133
}
2145
2134
2146
- zip_zip_forall (args1, args2, tycon1.typeParams) {
2135
+ (args1, args2, tycon1.typeParams).zipped.exists {
2147
2136
(arg1, arg2, tparam) =>
2148
2137
val v = tparam.paramVariance
2149
2138
if (v > 0 )
2150
- covariantIntersecting (arg1, arg2, tparam)
2139
+ covariantDisjoint (arg1, arg2, tparam)
2151
2140
else if (v < 0 )
2152
2141
// Contravariant case: a value where this type parameter is
2153
2142
// instantiated to `Any` belongs to both types.
2154
- true
2143
+ false
2155
2144
else
2156
- covariantIntersecting (arg1, arg2, tparam) && ( isSameType(arg1, arg2) || {
2145
+ covariantDisjoint (arg1, arg2, tparam) || ! isSameType(arg1, arg2) && {
2157
2146
// We can only trust a "no" from `isSameType` when both
2158
2147
// `arg1` and `arg2` are fully instantiated.
2159
- val fullyInstantiated = new TypeAccumulator [Boolean ] {
2148
+ def fullyInstantiated ( tp : Type ) : Boolean = new TypeAccumulator [Boolean ] {
2160
2149
override def apply (x : Boolean , t : Type ) =
2161
2150
x && {
2162
2151
t match {
@@ -2165,34 +2154,36 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
2165
2154
case _ => foldOver(x, t)
2166
2155
}
2167
2156
}
2168
- }
2169
- ! (fullyInstantiated.apply(true , arg1) &&
2170
- fullyInstantiated.apply(true , arg2))
2171
- })
2157
+ }.apply(true , tp)
2158
+ fullyInstantiated(arg1) && fullyInstantiated(arg2)
2159
+ }
2172
2160
}
2173
2161
case (tp1 : HKLambda , tp2 : HKLambda ) =>
2174
- intersecting (tp1.resType, tp2.resType)
2162
+ disjoint (tp1.resType, tp2.resType)
2175
2163
case (_ : HKLambda , _) =>
2176
- // The intersection is ill kinded and therefore empty .
2177
- false
2164
+ // The intersection of these two types would be ill kinded, they are therefore disjoint .
2165
+ true
2178
2166
case (_, _ : HKLambda ) =>
2179
- false
2167
+ true
2180
2168
case (tp1 : OrType , _) =>
2181
- intersecting (tp1.tp1, tp2) || intersecting (tp1.tp2, tp2)
2169
+ disjoint (tp1.tp1, tp2) && disjoint (tp1.tp2, tp2)
2182
2170
case (_, tp2 : OrType ) =>
2183
- intersecting(tp1, tp2.tp1) || intersecting(tp1, tp2.tp2)
2171
+ disjoint(tp1, tp2.tp1) && disjoint(tp1, tp2.tp2)
2172
+ case (tp1 : AndType , tp2 : AndType ) =>
2173
+ (disjoint(tp1.tp1, tp2.tp1) || disjoint(tp1.tp2, tp2.tp2)) &&
2174
+ (disjoint(tp1.tp1, tp2.tp2) || disjoint(tp1.tp2, tp2.tp1))
2184
2175
case (tp1 : AndType , _) =>
2185
- intersecting (tp1.tp1, tp2) && intersecting(tp1.tp2 , tp2) && intersecting (tp1.tp1, tp1. tp2)
2176
+ disjoint (tp1.tp2, tp2) || disjoint (tp1.tp1, tp2)
2186
2177
case (_, tp2 : AndType ) =>
2187
- intersecting (tp1, tp2.tp1) && intersecting(tp1, tp2.tp2) && intersecting(tp2. tp1, tp2.tp2 )
2178
+ disjoint (tp1, tp2.tp2) || disjoint( tp1, tp2.tp1 )
2188
2179
case (tp1 : TypeProxy , tp2 : TypeProxy ) =>
2189
- intersecting (tp1.underlying, tp2) && intersecting (tp1, tp2.underlying)
2180
+ disjoint (tp1.underlying, tp2) || disjoint (tp1, tp2.underlying)
2190
2181
case (tp1 : TypeProxy , _) =>
2191
- intersecting (tp1.underlying, tp2)
2182
+ disjoint (tp1.underlying, tp2)
2192
2183
case (_, tp2 : TypeProxy ) =>
2193
- intersecting (tp1, tp2.underlying)
2184
+ disjoint (tp1, tp2.underlying)
2194
2185
case _ =>
2195
- true
2186
+ false
2196
2187
}
2197
2188
}
2198
2189
}
@@ -2321,6 +2312,24 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
2321
2312
case _ =>
2322
2313
cas
2323
2314
}
2315
+ def widenAbstractTypes (tp : Type ): Type = new TypeMap {
2316
+ def apply (tp : Type ) = tp match {
2317
+ case tp : TypeRef =>
2318
+ if (tp.symbol.isAbstractOrParamType | tp.symbol.isOpaqueAlias)
2319
+ WildcardType
2320
+ else tp.info match {
2321
+ case TypeAlias (alias) =>
2322
+ val alias1 = widenAbstractTypes(alias)
2323
+ if (alias1 ne alias) alias1 else tp
2324
+ case _ => mapOver(tp)
2325
+ }
2326
+
2327
+ case tp : TypeVar if ! tp.isInstantiated => WildcardType
2328
+ case _ : TypeParamRef => WildcardType
2329
+ case _ => mapOver(tp)
2330
+ }
2331
+ }.apply(tp)
2332
+
2324
2333
val defn .MatchCase (pat, body) = cas1
2325
2334
if (isSubType(scrut, pat))
2326
2335
// `scrut` is a subtype of `pat`: *It's a Match!*
@@ -2333,12 +2342,14 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
2333
2342
body
2334
2343
}
2335
2344
}
2336
- else if (intersecting( scrut, pat))
2345
+ else if (isSubType(widenAbstractTypes( scrut), widenAbstractTypes( pat) ))
2337
2346
Some (NoType )
2338
- else
2347
+ else if (disjoint(scrut, pat))
2339
2348
// We found a proof that `scrut` and `pat` are incompatible.
2340
2349
// The search continues.
2341
2350
None
2351
+ else
2352
+ Some (NoType )
2342
2353
}
2343
2354
2344
2355
def recur (cases : List [Type ]): Type = cases match {
0 commit comments