Skip to content

Commit 98e9102

Browse files
oderskyKordyjan
authored andcommitted
Allow uninstantiated match parameters in some cases
Allow uninstantiated match parameters if the result of the match does not depend on them.
1 parent decfade commit 98e9102

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
@@ -2860,7 +2860,7 @@ object TrackingTypeComparer:
28602860
case Reduced(tp: Type)
28612861
case Disjoint
28622862
case Stuck
2863-
case NoInstance(param: Name, bounds: TypeBounds)
2863+
case NoInstance(fails: List[(Name, TypeBounds)])
28642864

28652865
class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
28662866
import TrackingTypeComparer.*
@@ -2906,25 +2906,25 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
29062906
def paramInstances(canApprox: Boolean) = new TypeAccumulator[Array[Type]]:
29072907
def apply(insts: Array[Type], t: Type) = t match
29082908
case param @ TypeParamRef(b, n) if b eq caseLambda =>
2909-
insts(n) = {
2909+
insts(n) =
29102910
if canApprox then
2911-
approximation(param, fromBelow = variance >= 0)
2911+
approximation(param, fromBelow = variance >= 0).simplified
29122912
else constraint.entry(param) match
29132913
case entry: TypeBounds =>
29142914
val lo = fullLowerBound(param)
29152915
val hi = fullUpperBound(param)
2916-
if isSubType(hi, lo) then lo else TypeBounds(lo, hi)
2916+
if isSubType(hi, lo) then lo.simplified else Range(lo, hi)
29172917
case inst =>
29182918
assert(inst.exists, i"param = $param\nconstraint = $constraint")
2919-
inst
2920-
}.simplified
2919+
inst.simplified
29212920
insts
29222921
case _ =>
29232922
foldOver(insts, t)
29242923

2925-
def instantiateParams(inst: Array[Type]) = new TypeMap {
2924+
def instantiateParams(insts: Array[Type]) = new ApproximatingTypeMap {
2925+
variance = 0
29262926
def apply(t: Type) = t match {
2927-
case t @ TypeParamRef(b, n) if b `eq` caseLambda => inst(n)
2927+
case t @ TypeParamRef(b, n) if b `eq` caseLambda => insts(n)
29282928
case t: LazyRef => apply(t.ref)
29292929
case _ => mapOver(t)
29302930
}
@@ -2957,11 +2957,15 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
29572957
caseLambda match
29582958
case caseLambda: HKTypeLambda =>
29592959
val instances = paramInstances(canApprox)(new Array(caseLambda.paramNames.length), pat)
2960-
instances.indices.find(instances(_).isInstanceOf[TypeBounds]) match
2961-
case Some(i) if !canApprox =>
2962-
MatchResult.NoInstance(caseLambda.paramNames(i), instances(i).bounds)
2963-
case _ =>
2964-
MatchResult.Reduced(instantiateParams(instances)(body).simplified)
2960+
instantiateParams(instances)(body) match
2961+
case Range(lo, hi) =>
2962+
MatchResult.NoInstance {
2963+
caseLambda.paramNames.zip(instances).collect {
2964+
case (name, Range(lo, hi)) => (name, TypeBounds(lo, hi))
2965+
}
2966+
}
2967+
case redux =>
2968+
MatchResult.Reduced(redux.simplified)
29652969
case _ =>
29662970
MatchResult.Reduced(body)
29672971

@@ -2985,8 +2989,8 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
29852989
case MatchResult.Stuck =>
29862990
MatchTypeTrace.stuck(scrut, cas, remaining1)
29872991
NoType
2988-
case MatchResult.NoInstance(pname, bounds) =>
2989-
MatchTypeTrace.noInstance(scrut, cas, pname, bounds)
2992+
case MatchResult.NoInstance(fails) =>
2993+
MatchTypeTrace.noInstance(scrut, cas, fails)
29902994
NoType
29912995
case MatchResult.Reduced(tp) =>
29922996
tp

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6013,7 +6013,7 @@ object Types {
60136013
/** A range of possible types between lower bound `lo` and upper bound `hi`.
60146014
* Only used internally in `ApproximatingTypeMap`.
60156015
*/
6016-
private case class Range(lo: Type, hi: Type) extends UncachedGroundType {
6016+
case class Range(lo: Type, hi: Type) extends UncachedGroundType {
60176017
assert(!lo.isInstanceOf[Range])
60186018
assert(!hi.isInstanceOf[Range])
60196019

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)