Skip to content

Commit 521ce95

Browse files
Always use baseType when constraining patternTp with scrutineeTp
In the following example: ``` type Cond[B <: Boolean] <: Tuple2[String, String] = B match ... type Decoded[B <: Boolean] = Cond[B] match case (h1, _) => Int ``` When constraining the `(h1, _)` pattern with `Cond[B]`, we incorrectly assumed we could constrain h1 with B, because `Cond[B]` is an applied type of which the baseType is Tuple2. The issue can be fixed in constrainSimplePatternType by obtaining the baseType for both the patternTp and scrutineeTp, with the most general base of the two. So in the above example, we wound constrain `B` with String by obtaining `(String, String)` from `Cond[B]`.
1 parent 960858d commit 521ce95

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala

+5-7
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,8 @@ trait PatternTypeConstrainer { self: TypeComparer =>
200200
*
201201
* This function expects to receive two types (scrutinee and pattern), both
202202
* of which have class symbols, one of which is derived from another. If the
203-
* type "being derived from" is an applied type, it will 1) "upcast" the
204-
* deriving type to an applied type with the same constructor and 2) infer
203+
* type "being derived from" is an applied type, it will 1) "upcast" both
204+
* types to an applied type with the same constructor and 2) infer
205205
* constraints for the applied types' arguments that follow from both
206206
* types being inhabited by one value (the scrutinee).
207207
*
@@ -252,11 +252,9 @@ trait PatternTypeConstrainer { self: TypeComparer =>
252252
val scrutineeCls = scrutineeTp.classSymbol
253253

254254
// NOTE: we already know that there is a derives-from relationship in either direction
255-
val upcastPattern =
256-
patternCls.derivesFrom(scrutineeCls)
257-
258-
val pt = if upcastPattern then patternTp.baseType(scrutineeCls) else patternTp
259-
val tp = if !upcastPattern then scrutineeTp.baseType(patternCls) else scrutineeTp
255+
val base = if patternCls.derivesFrom(scrutineeCls) then scrutineeCls else patternCls
256+
val pt = patternTp.baseType(base)
257+
val tp = scrutineeTp.baseType(base)
260258

261259
val assumeInvariantRefinement =
262260
migrateTo3 || forceInvariantRefinement || refinementIsInvariant(patternTp)

tests/pos/i19706.scala

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
import scala.compiletime.ops.string.{Length, Matches, Substring}
3+
4+
def emptyContext(): Unit =
5+
summon[Decoded["Tuple(0, EmptyTuple)"] =:= 0 *: EmptyTuple]
6+
7+
type Decoded[S <: String] = Matches[S, "Tuple(.+, .+)"] match
8+
case true => Parsed[Substring[S, 6, 19], 0, ""] match
9+
case (h, t) => Decoded["0"] *: EmptyTuple
10+
case false => 0
11+
12+
type Parsed[S <: String, I <: Int, A <: String] <: (String, String) = Matches[S, "other"] match
13+
case true => I match
14+
case 1 => ("", "")
15+
case _ => Parsed[Substring[S, 1, Length[S]], I, ""]
16+
case false => ("0", "EmptyTuple")
17+
18+
19+
object Minimization:
20+
21+
type Cond[B <: Boolean] <: Tuple2[String, String] = B match
22+
case true => ("", "")
23+
case false => ("a", "b")
24+
25+
type Decoded[B <: Boolean] = Cond[B] match
26+
case (h1, _) => Int
27+
28+
val _: Decoded[false] = 1
29+

0 commit comments

Comments
 (0)