@@ -2376,6 +2376,32 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
23762376 def covariantDisjoint (tp1 : Type , tp2 : Type , tparam : TypeParamInfo ): Boolean =
23772377 provablyDisjoint(tp1, tp2) && typeparamCorrespondsToField(tycon1, tparam)
23782378
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+
23792405 args1.lazyZip(args2).lazyZip(tycon1.typeParams).exists {
23802406 (arg1, arg2, tparam) =>
23812407 val v = tparam.paramVarianceSign
@@ -2386,21 +2412,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
23862412 // instantiated to `Any` belongs to both types.
23872413 false
23882414 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)
24042416 }
24052417 case (tp1 : HKLambda , tp2 : HKLambda ) =>
24062418 provablyDisjoint(tp1.resType, tp2.resType)
0 commit comments