aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-09-26 13:40:59 +0200
committerFelix Mulder <felix.mulder@gmail.com>2016-10-10 13:25:35 +0200
commit33d44903ec95cff9b79523683175733fd49ba140 (patch)
tree86b70814ee0a854609ab4397d586b16e145bfa6e
parentaa559359bb55729913d34588462542f10c42e147 (diff)
downloaddotty-33d44903ec95cff9b79523683175733fd49ba140.tar.gz
dotty-33d44903ec95cff9b79523683175733fd49ba140.tar.bz2
dotty-33d44903ec95cff9b79523683175733fd49ba140.zip
Make `typeDiff` aware of placeholder types
-rw-r--r--src/dotty/tools/dotc/printing/Formatting.scala55
-rw-r--r--src/dotty/tools/dotc/reporting/diagnostic/messages.scala4
-rw-r--r--tests/repl/errmsgs.check14
3 files changed, 45 insertions, 28 deletions
diff --git a/src/dotty/tools/dotc/printing/Formatting.scala b/src/dotty/tools/dotc/printing/Formatting.scala
index 89f9eb814..dd391ea80 100644
--- a/src/dotty/tools/dotc/printing/Formatting.scala
+++ b/src/dotty/tools/dotc/printing/Formatting.scala
@@ -116,6 +116,7 @@ object Formatting {
seen.record(super.polyParamNameString(param), param)
}
+ /** Create explanation for single `Recorded` type or symbol */
def explanation(entry: Recorded)(implicit ctx: Context): String = {
def boundStr(bound: Type, default: ClassSymbol, cmp: String) =
if (bound.isRef(default)) "" else i"$cmp $bound"
@@ -144,6 +145,7 @@ object Formatting {
}
}
+ /** Turns a `Seen => String` to produce a `where: T is...` clause */
private def explanations(seen: Seen)(implicit ctx: Context): String = {
def needsExplanation(entry: Recorded) = entry match {
case param: PolyParam => ctx.typerState.constraint.contains(param)
@@ -168,41 +170,56 @@ object Formatting {
val explainParts = toExplain.map { case (str, entry) => (str, explanation(entry)) }
val explainLines = columnar(explainParts)
- if (explainLines.isEmpty) "" else i"$explainLines%\n%\n"
+ if (explainLines.isEmpty) "" else i"where: $explainLines%\n %\n"
}
+ /** Context with correct printer set for explanations */
private def explainCtx(seen: Seen)(implicit ctx: Context): Context = ctx.printer match {
case dp: ExplainingPrinter =>
ctx // re-use outer printer and defer explanation to it
case _ => ctx.fresh.setPrinterFn(ctx => new ExplainingPrinter(seen)(ctx))
}
+ /** Entrypoint for explanation string interpolator:
+ *
+ * ```
+ * ex"disambiguate $tpe1 and $tpe2"
+ * ```
+ */
def explained2(op: Context => String)(implicit ctx: Context): String = {
val seen = new Seen
op(explainCtx(seen)) ++ explanations(seen)
}
- def disambiguateTypes(args: Type*)(implicit ctx: Context): String = {
+ /** When getting a type mismatch it is useful to disambiguate placeholders like:
+ *
+ * ```
+ * found: List[Int]
+ * required: List[T]
+ * where: T is a type in the initalizer of value s which is an alias of
+ * String
+ * ```
+ *
+ * @return the `where` section as well as the printing context for the
+ * placeholders - `("T is a...", printCtx)`
+ */
+ def disambiguateTypes(args: Type*)(implicit ctx: Context): (String, Context) = {
val seen = new Seen
- object polyparams extends TypeTraverser {
- def traverse(tp: Type): Unit = tp match {
- case tp: TypeRef =>
- seen.record(tp.show(explainCtx(seen)), tp.symbol)
- traverseChildren(tp)
- case tp: TermRef =>
- seen.record(tp.show(explainCtx(seen)), tp.symbol)
- traverseChildren(tp)
- case tp: PolyParam =>
- seen.record(tp.show(explainCtx(seen)), tp)
- traverseChildren(tp)
- case _ =>
- traverseChildren(tp)
- }
- }
- args.foreach(polyparams.traverse)
- explanations(seen)
+ val printCtx = explainCtx(seen)
+ args.foreach(_.show(printCtx)) // showing each member will put it into `seen`
+ (explanations(seen), printCtx)
}
+ /** This method will produce a colored type diff from the given arguments.
+ * The idea is to do this for known cases that are useful and then fall back
+ * on regular syntax highlighting for the cases which are unhandled.
+ *
+ * Please not that if used in combination with `disambiguateTypes` the
+ * correct `Context` for printing should also be passed when calling the
+ * method.
+ *
+ * @return the (found, expected) with coloring to highlight the difference
+ */
def typeDiff(found: Type, expected: Type)(implicit ctx: Context): (String, String) = {
(found, expected) match {
case (rf1: RefinedType, rf2: RefinedType) =>
diff --git a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
index 009636593..01cf00cf7 100644
--- a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
+++ b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
@@ -216,8 +216,8 @@ object messages {
case class TypeMismatch(found: Type, expected: Type, whyNoMatch: String = "")(implicit ctx: Context)
extends Message("E006") {
val kind = "Type Mismatch"
- private val where = Formatting.disambiguateTypes(found, expected)
- private val (fnd, exp) = Formatting.typeDiff(found, expected)
+ private val (where, printCtx) = Formatting.disambiguateTypes(found, expected)
+ private val (fnd, exp) = Formatting.typeDiff(found, expected)(printCtx)
val msg =
s"""|found: $fnd
|required: $exp
diff --git a/tests/repl/errmsgs.check b/tests/repl/errmsgs.check
index 8f86aac08..b8cff5ba2 100644
--- a/tests/repl/errmsgs.check
+++ b/tests/repl/errmsgs.check
@@ -34,7 +34,7 @@ scala> val a: Inv[String] = new Inv(new Inv(1))
found: Inv[T]
required: String
- T is a type variable with constraint >: Int(1)
+ where: T is a type variable with constraint >: Int(1)
scala> val b: Inv[String] = new Inv(1)
-- [E006] Type Mismatch Error: <console> -------------------------------------------------------------------------------
4:val b: Inv[String] = new Inv(1)
@@ -61,16 +61,16 @@ scala> abstract class C {
8: var y: T = x
^
found: C.this.T(C.this.x)
- required: T
+ required: T'
- T is a type in class C
- T' is a type in the initalizer of value s which is an alias of String
+ where: T is a type in class C
+ T' is a type in the initalizer of value s which is an alias of String
-- [E006] Type Mismatch Error: <console> -------------------------------------------------------------------------------
12: val z: T = y
^
found: T(y)
- required: T
+ required: T'
- T is a type in the initalizer of value s which is an alias of String
- T' is a type in method f which is an alias of Int
+ where: T is a type in the initalizer of value s which is an alias of String
+ T' is a type in method f which is an alias of Int
scala> :quit