Skip to content

Commit 2df96f9

Browse files
committed
Allow uninstantiated match parameters in some cases
Allow uninstantiated match parameters if the result of the match does not depend on them.
1 parent d9ef974 commit 2df96f9

File tree

9 files changed

+116
-77
lines changed

9 files changed

+116
-77
lines changed

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ object MatchTypeTrace:
1414
case TryReduce(scrut: Type)
1515
case NoMatches(scrut: Type, cases: List[Type])
1616
case Stuck(scrut: Type, stuckCase: Type, otherCases: List[Type])
17-
case NoInstance(scrut: Type, stuckCase: Type, pname: Name, bounds: TypeBounds)
17+
case NoInstance(scrut: Type, stuckCase: Type, fails: List[(Name, TypeBounds)])
1818
case EmptyScrutinee(scrut: Type)
1919
import TraceEntry._
2020

@@ -64,8 +64,8 @@ object MatchTypeTrace:
6464
def stuck(scrut: Type, stuckCase: Type, otherCases: List[Type])(using Context) =
6565
matchTypeFail(Stuck(scrut, stuckCase, otherCases))
6666

67-
def noInstance(scrut: Type, stuckCase: Type, pname: Name, bounds: TypeBounds)(using Context) =
68-
matchTypeFail(NoInstance(scrut, stuckCase, pname, bounds))
67+
def noInstance(scrut: Type, stuckCase: Type, fails: List[(Name, TypeBounds)])(using Context) =
68+
matchTypeFail(NoInstance(scrut, stuckCase, fails))
6969

7070
/** Record a failure that scrutinee `scrut` is provably empty.
7171
* Only the first failure is recorded.
@@ -87,7 +87,7 @@ object MatchTypeTrace:
8787
case _ =>
8888
op
8989

90-
private def caseText(tp: Type)(using Context): String = tp match
90+
def caseText(tp: Type)(using Context): String = tp match
9191
case tp: HKTypeLambda => caseText(tp.resultType)
9292
case defn.MatchCase(any, body) if any eq defn.AnyType => i"case _ => $body"
9393
case defn.MatchCase(pat, body) => i"case $pat => $body"
@@ -119,10 +119,13 @@ object MatchTypeTrace:
119119
| Therefore, reduction cannot advance to the remaining case$s
120120
|
121121
| ${casesText(otherCases)}"""
122-
case NoInstance(scrut, stuckCase, pname, bounds) =>
122+
case NoInstance(scrut, stuckCase, fails) =>
123+
def params = if fails.length == 1 then "parameter" else "parameters"
123124
i""" failed since selector $scrut
124-
| does not uniquely determine parameter $pname in ${caseText(stuckCase)}
125-
| The computed bounds for the parameter are: $bounds."""
125+
| does not uniquely determine $params ${fails.map(_._1)}%, % in
126+
| ${caseText(stuckCase)}
127+
| The computed bounds for the $params are:
128+
| ${fails.map((name, bounds) => i"$name$bounds")}%\n %"""
126129

127130
def noMatchesText(scrut: Type, cases: List[Type])(using Context): String =
128131
i"""failed since selector $scrut

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

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2856,7 +2856,7 @@ object TrackingTypeComparer:
28562856
case Reduced(tp: Type)
28572857
case Disjoint
28582858
case Stuck
2859-
case NoInstance(param: Name, bounds: TypeBounds)
2859+
case NoInstance(fails: List[(Name, TypeBounds)])
28602860

28612861
class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
28622862
import TrackingTypeComparer.*
@@ -2902,25 +2902,25 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
29022902
def paramInstances(canApprox: Boolean) = new TypeAccumulator[Array[Type]]:
29032903
def apply(insts: Array[Type], t: Type) = t match
29042904
case param @ TypeParamRef(b, n) if b eq caseLambda =>
2905-
insts(n) = {
2905+
insts(n) =
29062906
if canApprox then
2907-
approximation(param, fromBelow = variance >= 0)
2907+
approximation(param, fromBelow = variance >= 0).simplified
29082908
else constraint.entry(param) match
29092909
case entry: TypeBounds =>
29102910
val lo = fullLowerBound(param)
29112911
val hi = fullUpperBound(param)
2912-
if isSubType(hi, lo) then lo else TypeBounds(lo, hi)
2912+
if isSubType(hi, lo) then lo.simplified else Range(lo, hi)
29132913
case inst =>
29142914
assert(inst.exists, i"param = $param\nconstraint = $constraint")
2915-
inst
2916-
}.simplified
2915+
inst.simplified
29172916
insts
29182917
case _ =>
29192918
foldOver(insts, t)
29202919

2921-
def instantiateParams(inst: Array[Type]) = new TypeMap {
2920+
def instantiateParams(insts: Array[Type]) = new ApproximatingTypeMap {
2921+
variance = 0
29222922
def apply(t: Type) = t match {
2923-
case t @ TypeParamRef(b, n) if b `eq` caseLambda => inst(n)
2923+
case t @ TypeParamRef(b, n) if b `eq` caseLambda => insts(n)
29242924
case t: LazyRef => apply(t.ref)
29252925
case _ => mapOver(t)
29262926
}
@@ -2953,11 +2953,15 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
29532953
caseLambda match
29542954
case caseLambda: HKTypeLambda =>
29552955
val instances = paramInstances(canApprox)(new Array(caseLambda.paramNames.length), pat)
2956-
instances.indices.find(instances(_).isInstanceOf[TypeBounds]) match
2957-
case Some(i) if !canApprox =>
2958-
MatchResult.NoInstance(caseLambda.paramNames(i), instances(i).bounds)
2959-
case _ =>
2960-
MatchResult.Reduced(instantiateParams(instances)(body).simplified)
2956+
instantiateParams(instances)(body) match
2957+
case Range(lo, hi) =>
2958+
MatchResult.NoInstance {
2959+
caseLambda.paramNames.zip(instances).collect {
2960+
case (name, Range(lo, hi)) => (name, TypeBounds(lo, hi))
2961+
}
2962+
}
2963+
case redux =>
2964+
MatchResult.Reduced(redux.simplified)
29612965
case _ =>
29622966
MatchResult.Reduced(body)
29632967

@@ -2981,8 +2985,8 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
29812985
case MatchResult.Stuck =>
29822986
MatchTypeTrace.stuck(scrut, cas, remaining1)
29832987
NoType
2984-
case MatchResult.NoInstance(pname, bounds) =>
2985-
MatchTypeTrace.noInstance(scrut, cas, pname, bounds)
2988+
case MatchResult.NoInstance(fails) =>
2989+
MatchTypeTrace.noInstance(scrut, cas, fails)
29862990
NoType
29872991
case MatchResult.Reduced(tp) =>
29882992
tp

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5989,7 +5989,7 @@ object Types {
59895989
/** A range of possible types between lower bound `lo` and upper bound `hi`.
59905990
* Only used internally in `ApproximatingTypeMap`.
59915991
*/
5992-
private case class Range(lo: Type, hi: Type) extends UncachedGroundType {
5992+
case class Range(lo: Type, hi: Type) extends UncachedGroundType {
59935993
assert(!lo.isInstanceOf[Range])
59945994
assert(!hi.isInstanceOf[Range])
59955995

tests/neg/6570-1.check

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,19 @@
1414
-- [E007] Type Mismatch Error: tests/neg/6570-1.scala:36:54 ------------------------------------------------------------
1515
36 | def foo[T <: Cov[Box[Int]]](c: Root[T]): Trait2 = c.thing // error
1616
| ^^^^^^^
17-
| Found: M[T]
18-
| Required: Trait2
17+
| Found: M[T]
18+
| Required: Trait2
1919
|
20-
| where: T is a type in method foo with bounds <: Cov[Box[Int]]
20+
| where: T is a type in method foo with bounds <: Cov[Box[Int]]
2121
|
2222
|
23-
| Note: a match type could not be fully reduced:
23+
| Note: a match type could not be fully reduced:
2424
|
25-
| trying to reduce M[T]
26-
| failed since selector T
27-
| does not uniquely determine parameter x in case Cov[x] => N[x]
28-
| The computed bounds for the parameter are: >: Box[Int].
25+
| trying to reduce M[T]
26+
| failed since selector T
27+
| does not uniquely determine parameter x in
28+
| case Cov[x] => N[x]
29+
| The computed bounds for the parameter are:
30+
| x >: Box[Int]
2931
|
3032
| longer explanation available when compiling with `-explain`

tests/neg/i11982.check

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,4 @@
1-
-- [E057] Type Mismatch Error: tests/neg/i11982.scala:9:34 -------------------------------------------------------------
2-
9 | b: ValueOf[Tuple.Head[Tuple.Tail[X]]] // error
3-
| ^
4-
| Type argument Tuple.Tail[X] does not conform to upper bound NonEmptyTuple
5-
|
6-
| Note: a match type could not be fully reduced:
7-
|
8-
| trying to reduce Tuple.Tail[X]
9-
| failed since selector X
10-
| does not uniquely determine parameter xs in case _ *: xs => xs
11-
| The computed bounds for the parameter are: >: Any *: EmptyTuple.type <: Tuple.
12-
|
13-
| longer explanation available when compiling with `-explain`
14-
-- [E057] Type Mismatch Error: tests/neg/i11982.scala:10:38 ------------------------------------------------------------
15-
10 | ): Tuple2[Tuple.Head[X], Tuple.Head[Tuple.Tail[X]]] = // error
1+
-- Error: tests/neg/i11982.scala:22:38 ---------------------------------------------------------------------------------
2+
22 | val p1: ("msg", 42) = unpair[Tshape] // error: no singleton value for Any
163
| ^
17-
| Type argument Tuple.Tail[X] does not conform to upper bound NonEmptyTuple
18-
|
19-
| Note: a match type could not be fully reduced:
20-
|
21-
| trying to reduce Tuple.Tail[X]
22-
| failed since selector X
23-
| does not uniquely determine parameter xs in case _ *: xs => xs
24-
| The computed bounds for the parameter are: >: Any *: EmptyTuple.type <: Tuple.
25-
|
26-
| longer explanation available when compiling with `-explain`
27-
-- [E057] Type Mismatch Error: tests/neg/i11982.scala:12:25 ------------------------------------------------------------
28-
12 | type BB = Tuple.Head[Tuple.Tail[X]] // error
29-
| ^
30-
| Type argument Tuple.Tail[X] does not conform to upper bound NonEmptyTuple
31-
|
32-
| Note: a match type could not be fully reduced:
33-
|
34-
| trying to reduce Tuple.Tail[X]
35-
| failed since selector X
36-
| does not uniquely determine parameter xs in case _ *: xs => xs
37-
| The computed bounds for the parameter are: >: Any *: EmptyTuple.type <: Tuple.
38-
|
39-
| longer explanation available when compiling with `-explain`
4+
| No singleton value available for Any.

tests/neg/i11982.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ object Unpair {
66

77
def unpair[X <: Tuple2[?, ?]](
88
using a: ValueOf[Tuple.Head[X]],
9-
b: ValueOf[Tuple.Head[Tuple.Tail[X]]] // error
10-
): Tuple2[Tuple.Head[X], Tuple.Head[Tuple.Tail[X]]] = // error
9+
b: ValueOf[Tuple.Head[Tuple.Tail[X]]]
10+
): Tuple2[Tuple.Head[X], Tuple.Head[Tuple.Tail[X]]] =
1111
type AA = Tuple.Head[X]
12-
type BB = Tuple.Head[Tuple.Tail[X]] // error
12+
type BB = Tuple.Head[Tuple.Tail[X]]
1313
pair[AA, BB](using a, b)
1414
}
1515

@@ -19,7 +19,7 @@ object UnpairApp {
1919
type Tshape = ("msg", 42)
2020

2121
// the following won't compile when in the same file as Unpair
22-
val p1: ("msg", 42) = unpair[Tshape]
22+
val p1: ("msg", 42) = unpair[Tshape] // error: no singleton value for Any
2323

2424
@main def pairHello: Unit =
2525
assert(p1 == ("msg", 42))

tests/neg/i11982a.check

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
-- [E057] Type Mismatch Error: tests/neg/i11982a.scala:9:34 ------------------------------------------------------------
2+
9 | b: ValueOf[Tuple.Head[Tuple.Tail[X]]] // error
3+
| ^
4+
| Type argument Tuple.Tail[X] does not conform to upper bound NonEmptyTuple
5+
|
6+
| Note: a match type could not be fully reduced:
7+
|
8+
| trying to reduce Tuple.Tail[X]
9+
| failed since selector X
10+
| does not uniquely determine parameter xs in
11+
| case _ *: xs => xs
12+
| The computed bounds for the parameter are:
13+
| xs >: Any *: EmptyTuple.type <: Tuple
14+
|
15+
| longer explanation available when compiling with `-explain`
16+
-- [E057] Type Mismatch Error: tests/neg/i11982a.scala:10:38 -----------------------------------------------------------
17+
10 | ): Tuple2[Tuple.Head[X], Tuple.Head[Tuple.Tail[X]]] = // error
18+
| ^
19+
| Type argument Tuple.Tail[X] does not conform to upper bound NonEmptyTuple
20+
|
21+
| Note: a match type could not be fully reduced:
22+
|
23+
| trying to reduce Tuple.Tail[X]
24+
| failed since selector X
25+
| does not uniquely determine parameter xs in
26+
| case _ *: xs => xs
27+
| The computed bounds for the parameter are:
28+
| xs >: Any *: EmptyTuple.type <: Tuple
29+
|
30+
| longer explanation available when compiling with `-explain`
31+
-- [E057] Type Mismatch Error: tests/neg/i11982a.scala:12:25 -----------------------------------------------------------
32+
12 | type BB = Tuple.Head[Tuple.Tail[X]] // error
33+
| ^
34+
| Type argument Tuple.Tail[X] does not conform to upper bound NonEmptyTuple
35+
|
36+
| Note: a match type could not be fully reduced:
37+
|
38+
| trying to reduce Tuple.Tail[X]
39+
| failed since selector X
40+
| does not uniquely determine parameter xs in
41+
| case _ *: xs => xs
42+
| The computed bounds for the parameter are:
43+
| xs >: Any *: EmptyTuple.type <: Tuple
44+
|
45+
| longer explanation available when compiling with `-explain`

tests/neg/i11982a.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package tuplefun
2+
object Unpair {
3+
4+
def pair[A, B](using a: ValueOf[A], b: ValueOf[B]): Tuple2[A, B] =
5+
(a.value, b.value)
6+
7+
def unpair[X <: Tuple2[?, ?]](
8+
using a: ValueOf[Tuple.Head[X]],
9+
b: ValueOf[Tuple.Head[Tuple.Tail[X]]] // error
10+
): Tuple2[Tuple.Head[X], Tuple.Head[Tuple.Tail[X]]] = // error
11+
type AA = Tuple.Head[X]
12+
type BB = Tuple.Head[Tuple.Tail[X]] // error
13+
pair[AA, BB](using a, b)
14+
}

tests/neg/i13780.check

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111
|
1212
| trying to reduce Head[X]
1313
| failed since selector X
14-
| does not uniquely determine parameter a in case (a, b) => a
15-
| The computed bounds for the parameter are: >: Int.
14+
| does not uniquely determine parameters a, b in
15+
| case (a, b) => a
16+
| The computed bounds for the parameters are:
17+
| a >: Int
18+
| b >: Int
1619
|
1720
| longer explanation available when compiling with `-explain`
1821
-- [E007] Type Mismatch Error: tests/neg/i13780.scala:23:37 ------------------------------------------------------------
@@ -28,7 +31,10 @@
2831
|
2932
| trying to reduce Head[X]
3033
| failed since selector X
31-
| does not uniquely determine parameter a in case (a, b) => a
32-
| The computed bounds for the parameter are: >: String.
34+
| does not uniquely determine parameters a, b in
35+
| case (a, b) => a
36+
| The computed bounds for the parameters are:
37+
| a >: String
38+
| b >: String
3339
|
3440
| longer explanation available when compiling with `-explain`

0 commit comments

Comments
 (0)