From 85a94cd1f36432c431df53a3a8846dea7fdf1ab1 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Mon, 12 Feb 2018 18:57:24 +0100 Subject: [PATCH] Show GADT bounds in type mismatch message The inferred GADT bounds can be non-trivial so it makes sense to display them. This commit also showcases the now-improved GADT support in Dotty (both tests/pos/gadt-eval.scala and tests/neg/gadt-eval.scala used to compile, and both compile in Scala 2). --- .../tools/dotc/printing/Formatting.scala | 12 +++++-- tests/neg/gadt-eval.scala | 33 +++++++++++++++++++ tests/pos/gadt-eval.scala | 19 +++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 tests/neg/gadt-eval.scala create mode 100644 tests/pos/gadt-eval.scala diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index e9f88523d8b8..0d04f503ed84 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -168,7 +168,12 @@ object Formatting { case param: TypeParamRef => s"is a type variable${addendum("constraint", ctx.typeComparer.bounds(param))}" case sym: Symbol => - s"is a ${ctx.printer.kindString(sym)}${sym.showExtendedLocation}${addendum("bounds", sym.info)}" + val info = + if (ctx.gadt.bounds.contains(sym)) + sym.info & ctx.gadt.bounds(sym) + else + sym.info + s"is a ${ctx.printer.kindString(sym)}${sym.showExtendedLocation}${addendum("bounds", info)}" case tp: SkolemType => s"is an unknown value of type ${tp.widen.show}" } @@ -183,7 +188,10 @@ object Formatting { def needsExplanation(entry: Recorded) = entry match { case param: TypeParamRef => ctx.typerState.constraint.contains(param) case skolem: SkolemType => true - case _ => false + case sym: Symbol => + ctx.gadt.bounds.contains(sym) && ctx.gadt.bounds(sym) != TypeBounds.empty + case _ => + false } val toExplain: List[(String, Recorded)] = seen.toList.flatMap { diff --git a/tests/neg/gadt-eval.scala b/tests/neg/gadt-eval.scala new file mode 100644 index 000000000000..d4cfae39ee67 --- /dev/null +++ b/tests/neg/gadt-eval.scala @@ -0,0 +1,33 @@ +sealed trait Exp[T] +case class Lit(value: Int) extends Exp[Int] +case class Pair[A, B](fst: Exp[A], snd: Exp[B]) extends Exp[(A, B)] + +object Test { + def eval[T](e: Exp[T]): T = e match { + case Lit(x) => + x + case Pair(a, b) => + (eval(a), eval(a)) + // -- [E007] Type Mismatch Error: tests/neg/gadt-eval.scala:10:6 ------------------ + // 10 | (eval(a), eval(a)) + // | ^^^^^^^^^^^^^^^^^^ + // | found: (_$1, _$1) + // | required: T + // | + // | where: T is a type in method eval which is an alias of (_$1, _$2) + } + + def eval2[T](e: Exp[T]): T = e match { + case e: Lit => + e.value + case e: Pair[t1, t2] => + (eval(e.fst), eval(e.fst)) + //-- [E007] Type Mismatch Error: tests/neg/gadt-eval.scala:24:6 ------------------ + //24 | (eval(e.fst), eval(e.fst)) + // | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + // | found: (t1, t1) + // | required: T + // | + // | where: T is a type in method eval2 which is an alias of (t1, t2) + } +} diff --git a/tests/pos/gadt-eval.scala b/tests/pos/gadt-eval.scala new file mode 100644 index 000000000000..2cebba3f378d --- /dev/null +++ b/tests/pos/gadt-eval.scala @@ -0,0 +1,19 @@ +sealed trait Exp[T] +case class Lit(value: Int) extends Exp[Int] +case class Pair[A, B](fst: Exp[A], snd: Exp[B]) extends Exp[(A, B)] + +object Test { + def eval[T](e: Exp[T]): T = e match { + case Lit(x) => + x + case Pair(a, b) => + (eval(a), eval(b)) + } + + def eval2[T](e: Exp[T]): T = e match { + case e: Lit => + e.value + case e: Pair[t1, t2] => + (eval(e.fst), eval(e.snd)) + } +}