Skip to content

Commit d75e110

Browse files
authored
Merge pull request #3990 from dotty-staging/fix/gadt-error
Show GADT bounds in type mismatch message
2 parents 7f47b9d + 39af805 commit d75e110

File tree

4 files changed

+63
-4
lines changed

4 files changed

+63
-4
lines changed

compiler/src/dotty/tools/dotc/printing/Formatting.scala

+11-2
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,12 @@ object Formatting {
168168
case param: TypeParamRef =>
169169
s"is a type variable${addendum("constraint", ctx.typeComparer.bounds(param))}"
170170
case sym: Symbol =>
171-
s"is a ${ctx.printer.kindString(sym)}${sym.showExtendedLocation}${addendum("bounds", sym.info)}"
171+
val info =
172+
if (ctx.gadt.bounds.contains(sym))
173+
sym.info & ctx.gadt.bounds(sym)
174+
else
175+
sym.info
176+
s"is a ${ctx.printer.kindString(sym)}${sym.showExtendedLocation}${addendum("bounds", info)}"
172177
case tp: SkolemType =>
173178
s"is an unknown value of type ${tp.widen.show}"
174179
}
@@ -183,7 +188,11 @@ object Formatting {
183188
def needsExplanation(entry: Recorded) = entry match {
184189
case param: TypeParamRef => ctx.typerState.constraint.contains(param)
185190
case skolem: SkolemType => true
186-
case _ => false
191+
case sym: Symbol =>
192+
ctx.gadt.bounds.contains(sym) && ctx.gadt.bounds(sym) != TypeBounds.empty
193+
case _ =>
194+
assert(false, "unreachable")
195+
false
187196
}
188197

189198
val toExplain: List[(String, Recorded)] = seen.toList.flatMap {

compiler/src/dotty/tools/dotc/transform/PostTyper.scala

-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ import reporting.diagnostic.messages.{NotAMember, SuperCallsNotAllowedInline}
4444
* (11) Minimizes `call` fields of `Inline` nodes to just point to the toplevel
4545
* class from which code was inlined.
4646
*
47-
* (12) Converts GADT bounds into normal type bounds
48-
*
4947
* The reason for making this a macro transform is that some functions (in particular
5048
* super and protected accessors and instantiation checks) are naturally top-down and
5149
* don't lend themselves to the bottom-up approach of a mini phase. The other two functions

tests/neg/gadt-eval.scala

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
sealed trait Exp[T]
2+
case class Lit(value: Int) extends Exp[Int]
3+
case class Pair[A, B](fst: Exp[A], snd: Exp[B]) extends Exp[(A, B)]
4+
5+
object Test {
6+
def eval[T](e: Exp[T]): T = e match {
7+
case Lit(x) =>
8+
x
9+
case Pair(a, b) =>
10+
(eval(a), eval(a)) // error:
11+
// -- [E007] Type Mismatch Error: tests/neg/gadt-eval.scala:10:6 ------------------
12+
// 10 | (eval(a), eval(a))
13+
// | ^^^^^^^^^^^^^^^^^^
14+
// | found: (_$1, _$1)
15+
// | required: T
16+
// |
17+
// | where: T is a type in method eval which is an alias of (_$1, _$2)
18+
}
19+
20+
def eval2[T](e: Exp[T]): T = e match {
21+
case e: Lit =>
22+
e.value
23+
case e: Pair[t1, t2] =>
24+
(eval(e.fst), eval(e.fst)) // error:
25+
//-- [E007] Type Mismatch Error: tests/neg/gadt-eval.scala:24:6 ------------------
26+
//24 | (eval(e.fst), eval(e.fst))
27+
// | ^^^^^^^^^^^^^^^^^^^^^^^^^^
28+
// | found: (t1, t1)
29+
// | required: T
30+
// |
31+
// | where: T is a type in method eval2 which is an alias of (t1, t2)
32+
}
33+
}

tests/pos/gadt-eval.scala

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
sealed trait Exp[T]
2+
case class Lit(value: Int) extends Exp[Int]
3+
case class Pair[A, B](fst: Exp[A], snd: Exp[B]) extends Exp[(A, B)]
4+
5+
object Test {
6+
def eval[T](e: Exp[T]): T = e match {
7+
case Lit(x) =>
8+
x
9+
case Pair(a, b) =>
10+
(eval(a), eval(b))
11+
}
12+
13+
def eval2[T](e: Exp[T]): T = e match {
14+
case e: Lit =>
15+
e.value
16+
case e: Pair[t1, t2] =>
17+
(eval(e.fst), eval(e.snd))
18+
}
19+
}

0 commit comments

Comments
 (0)