diff --git a/compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala b/compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala index 38f8e19e2737..7942bbaa3d45 100644 --- a/compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala +++ b/compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala @@ -200,8 +200,8 @@ trait PatternTypeConstrainer { self: TypeComparer => * * This function expects to receive two types (scrutinee and pattern), both * of which have class symbols, one of which is derived from another. If the - * type "being derived from" is an applied type, it will 1) "upcast" the - * deriving type to an applied type with the same constructor and 2) infer + * type "being derived from" is an applied type, it will 1) "upcast" both + * types to an applied type with the same constructor and 2) infer * constraints for the applied types' arguments that follow from both * types being inhabited by one value (the scrutinee). * @@ -252,11 +252,9 @@ trait PatternTypeConstrainer { self: TypeComparer => val scrutineeCls = scrutineeTp.classSymbol // NOTE: we already know that there is a derives-from relationship in either direction - val upcastPattern = - patternCls.derivesFrom(scrutineeCls) - - val pt = if upcastPattern then patternTp.baseType(scrutineeCls) else patternTp - val tp = if !upcastPattern then scrutineeTp.baseType(patternCls) else scrutineeTp + val base = if patternCls.derivesFrom(scrutineeCls) then scrutineeCls else patternCls + val pt = patternTp.baseType(base) + val tp = scrutineeTp.baseType(base) val assumeInvariantRefinement = migrateTo3 || forceInvariantRefinement || refinementIsInvariant(patternTp) diff --git a/tests/pos/i19706.scala b/tests/pos/i19706.scala new file mode 100644 index 000000000000..ba66b3baf5c4 --- /dev/null +++ b/tests/pos/i19706.scala @@ -0,0 +1,29 @@ + +import scala.compiletime.ops.string.{Length, Matches, Substring} + +def emptyContext(): Unit = + summon[Decoded["Tuple(0, EmptyTuple)"] =:= 0 *: EmptyTuple] + +type Decoded[S <: String] = Matches[S, "Tuple(.+, .+)"] match + case true => Parsed[Substring[S, 6, 19], 0, ""] match + case (h, t) => Decoded["0"] *: EmptyTuple + case false => 0 + +type Parsed[S <: String, I <: Int, A <: String] <: (String, String) = Matches[S, "other"] match + case true => I match + case 1 => ("", "") + case _ => Parsed[Substring[S, 1, Length[S]], I, ""] + case false => ("0", "EmptyTuple") + + +object Minimization: + + type Cond[B <: Boolean] <: Tuple2[String, String] = B match + case true => ("", "") + case false => ("a", "b") + + type Decoded[B <: Boolean] = Cond[B] match + case (h1, _) => Int + + val _: Decoded[false] = 1 +