@@ -2376,6 +2376,32 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
2376
2376
def covariantDisjoint (tp1 : Type , tp2 : Type , tparam : TypeParamInfo ): Boolean =
2377
2377
provablyDisjoint(tp1, tp2) && typeparamCorrespondsToField(tycon1, tparam)
2378
2378
2379
+ // In the invariant case, we used a weaker version of disjointness:
2380
+ // we consider types not equal with respect to =:= to be disjoint
2381
+ // (under any context). This is fine because it matches the runtime
2382
+ // semantics of pattern matching. To implement a pattern such as
2383
+ // `case Inv[T] => ...`, one needs a type tag for `T` and the compiler
2384
+ // is used at runtime to check it the scrutinee's type is =:= to `T`.
2385
+ // Note that this is currently a theoretical concern since we Dotty
2386
+ // doesn't have type tags, meaning that users cannot write patterns
2387
+ // that do type tests on higher kinded types.
2388
+ def invariantDisjoint (tp1 : Type , tp2 : Type , tparam : TypeParamInfo ): Boolean =
2389
+ covariantDisjoint(tp1, tp2, tparam) || ! isSameType(tp1, tp2) && {
2390
+ // We can only trust a "no" from `isSameType` when both
2391
+ // `tp1` and `tp2` are fully instantiated.
2392
+ def fullyInstantiated (tp : Type ): Boolean = new TypeAccumulator [Boolean ] {
2393
+ override def apply (x : Boolean , t : Type ) =
2394
+ x && {
2395
+ t match {
2396
+ case tp : TypeRef if tp.symbol.isAbstractOrParamType => false
2397
+ case _ : SkolemType | _ : TypeVar => false
2398
+ case _ => foldOver(x, t)
2399
+ }
2400
+ }
2401
+ }.apply(true , tp)
2402
+ fullyInstantiated(tp1) && fullyInstantiated(tp2)
2403
+ }
2404
+
2379
2405
args1.lazyZip(args2).lazyZip(tycon1.typeParams).exists {
2380
2406
(arg1, arg2, tparam) =>
2381
2407
val v = tparam.paramVarianceSign
@@ -2386,21 +2412,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
2386
2412
// instantiated to `Any` belongs to both types.
2387
2413
false
2388
2414
else
2389
- covariantDisjoint(arg1, arg2, tparam) || ! isSameType(arg1, arg2) && {
2390
- // We can only trust a "no" from `isSameType` when both
2391
- // `arg1` and `arg2` are fully instantiated.
2392
- def fullyInstantiated (tp : Type ): Boolean = new TypeAccumulator [Boolean ] {
2393
- override def apply (x : Boolean , t : Type ) =
2394
- x && {
2395
- t match {
2396
- case tp : TypeRef if tp.symbol.isAbstractOrParamType => false
2397
- case _ : SkolemType | _ : TypeVar => false
2398
- case _ => foldOver(x, t)
2399
- }
2400
- }
2401
- }.apply(true , tp)
2402
- fullyInstantiated(arg1) && fullyInstantiated(arg2)
2403
- }
2415
+ invariantDisjoint(arg1, arg2, tparam)
2404
2416
}
2405
2417
case (tp1 : HKLambda , tp2 : HKLambda ) =>
2406
2418
provablyDisjoint(tp1.resType, tp2.resType)
0 commit comments