aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/ast/NavigateAST.scala2
-rw-r--r--src/dotty/tools/dotc/config/CompilerCommand.scala4
-rw-r--r--src/dotty/tools/dotc/core/Constraint.scala2
-rw-r--r--src/dotty/tools/dotc/core/Decorators.scala74
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala2
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala16
-rw-r--r--src/dotty/tools/dotc/core/SymbolLoaders.scala4
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala1
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala3
-rw-r--r--src/dotty/tools/dotc/core/Types.scala8
-rw-r--r--src/dotty/tools/dotc/core/classfile/ClassfileParser.scala27
-rw-r--r--src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala4
-rw-r--r--src/dotty/tools/dotc/printing/Disambiguation.scala86
-rw-r--r--src/dotty/tools/dotc/printing/Formatting.scala175
-rw-r--r--src/dotty/tools/dotc/printing/PlainPrinter.scala40
-rw-r--r--src/dotty/tools/dotc/printing/Printer.scala3
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala4
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala10
-rw-r--r--src/dotty/tools/dotc/transform/CheckReentrant.scala2
-rw-r--r--src/dotty/tools/dotc/transform/ExtensionMethods.scala26
-rw-r--r--src/dotty/tools/dotc/transform/PatternMatcher.scala5
-rw-r--r--src/dotty/tools/dotc/transform/Pickler.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala10
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala38
-rw-r--r--src/dotty/tools/dotc/typer/ErrorReporting.scala85
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala20
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala8
-rw-r--r--src/dotty/tools/dotc/typer/RefChecks.scala6
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala22
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala52
-rw-r--r--tests/neg/i1430.scala26
31 files changed, 420 insertions, 349 deletions
diff --git a/src/dotty/tools/dotc/ast/NavigateAST.scala b/src/dotty/tools/dotc/ast/NavigateAST.scala
index 782866bad..2b11f81f3 100644
--- a/src/dotty/tools/dotc/ast/NavigateAST.scala
+++ b/src/dotty/tools/dotc/ast/NavigateAST.scala
@@ -22,7 +22,7 @@ object NavigateAST {
Error(i"""no untyped tree for $tree, pos = ${tree.pos}, envelope = ${tree.envelope}
|best matching path =\n$loosePath%\n====\n%
|path positions = ${loosePath.map(_.pos)}
- |path envelopes = ${loosePath.map(_.envelope)}""".stripMargin)
+ |path envelopes = ${loosePath.map(_.envelope)}""")
}
/** The reverse path of untyped trees starting with a tree that closest matches
diff --git a/src/dotty/tools/dotc/config/CompilerCommand.scala b/src/dotty/tools/dotc/config/CompilerCommand.scala
index 2fe32b4d3..19ede3cec 100644
--- a/src/dotty/tools/dotc/config/CompilerCommand.scala
+++ b/src/dotty/tools/dotc/config/CompilerCommand.scala
@@ -13,7 +13,7 @@ object CompilerCommand extends DotClass {
/** The name of the command */
def cmdName = "scalac"
- private def explainAdvanced = "\n" + """
+ private def explainAdvanced = """
|-- Notes on option parsing --
|Boolean settings are always false unless set.
|Where multiple values are accepted, they should be comma-separated.
@@ -26,7 +26,7 @@ object CompilerCommand extends DotClass {
| example: -Ylog:erasure+ logs the erasure phase and the phase after the erasure phase.
| This is useful because during the tree transform of phase X, we often
| already are in phase X + 1.
- """.stripMargin.trim + "\n"
+ """
def shortUsage = s"Usage: $cmdName <options> <source files>"
diff --git a/src/dotty/tools/dotc/core/Constraint.scala b/src/dotty/tools/dotc/core/Constraint.scala
index e10523753..436b035dc 100644
--- a/src/dotty/tools/dotc/core/Constraint.scala
+++ b/src/dotty/tools/dotc/core/Constraint.scala
@@ -32,7 +32,7 @@ abstract class Constraint extends Showable {
def contains(tvar: TypeVar): Boolean
/** The constraint entry for given type parameter `param`, or NoType if `param` is not part of
- * the constraint domain.
+ * the constraint domain. Note: Low level, implementation dependent.
*/
def entry(param: PolyParam): Type
diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala
index 7d108a459..387e7e466 100644
--- a/src/dotty/tools/dotc/core/Decorators.scala
+++ b/src/dotty/tools/dotc/core/Decorators.scala
@@ -8,6 +8,7 @@ import util.Positions.Position, util.SourcePosition
import collection.mutable.ListBuffer
import dotty.tools.dotc.transform.TreeTransforms._
import scala.language.implicitConversions
+import printing.Formatting._
/** This object provides useful implicit decorators for types defined elsewhere */
object Decorators {
@@ -150,72 +151,23 @@ object Decorators {
implicit def sourcePos(pos: Position)(implicit ctx: Context): SourcePosition =
ctx.source.atPos(pos)
- /** The i"..." string interpolator adds two features to the s interpolator:
- * 1) On all Showables, `show` is called instead of `toString`
- * 2) Lists can be formatted using the desired separator between two `%` signs,
- * eg `i"myList = (${myList}%, %)"`
- */
implicit class StringInterpolators(val sc: StringContext) extends AnyVal {
- def i(args: Any*)(implicit ctx: Context): String = {
-
- def treatArg(arg: Any, suffix: String): (Any, String) = arg match {
- case arg: Seq[_] if suffix.nonEmpty && suffix.head == '%' =>
- val (rawsep, rest) = suffix.tail.span(_ != '%')
- val sep = StringContext.treatEscapes(rawsep)
- if (rest.nonEmpty) (arg map treatSingleArg mkString sep, rest.tail)
- else (arg, suffix)
- case _ =>
- (treatSingleArg(arg), suffix)
- }
-
- def treatSingleArg(arg: Any) : Any =
- try
- arg match {
- case arg: Showable => arg.show(ctx.addMode(Mode.FutureDefsOK))
- case _ => arg
- }
- catch {
- case ex: Exception => throw ex // s"(missing due to $ex)"
- }
+ /** General purpose string formatting */
+ def i(args: Any*)(implicit ctx: Context): String =
+ new StringFormatter(sc).assemble(args)
- val prefix :: suffixes = sc.parts.toList
- val (args1, suffixes1) = (args, suffixes).zipped.map(treatArg(_, _)).unzip
- new StringContext(prefix :: suffixes1.toList: _*).s(args1: _*)
- }
+ /** Formatting for error messages: Like `i` but suppress follow-on
+ * error messages after the first one if some of their arguments are "non-sensical".
+ */
+ def em(args: Any*)(implicit ctx: Context): String =
+ new ErrorMessageFormatter(sc).assemble(args)
- /** Lifted from scala.reflect.internal.util
- * A safe combination of [[scala.collection.immutable.StringLike#stripMargin]]
- * and [[scala.StringContext#raw]].
- *
- * The margin of each line is defined by whitespace leading up to a '|' character.
- * This margin is stripped '''before''' the arguments are interpolated into to string.
- *
- * String escape sequences are '''not''' processed; this interpolater is designed to
- * be used with triple quoted Strings.
- *
- * {{{
- * scala> val foo = "f|o|o"
- * foo: String = f|o|o
- * scala> sm"""|${foo}
- * |"""
- * res0: String =
- * "f|o|o
- * "
- * }}}
+ /** Formatting with added explanations: Like `em`, but add explanations to
+ * give more info about type variables and to disambiguate where needed.
*/
- final def sm(args: Any*): String = {
- def isLineBreak(c: Char) = c == '\n' || c == '\f' // compatible with StringLike#isLineBreak
- def stripTrailingPart(s: String) = {
- val (pre, post) = s.span(c => !isLineBreak(c))
- pre + post.stripMargin
- }
- val stripped: List[String] = sc.parts.toList match {
- case head :: tail => head.stripMargin :: (tail map stripTrailingPart)
- case Nil => Nil
- }
- new StringContext(stripped: _*).raw(args: _*)
- }
+ def ex(args: Any*)(implicit ctx: Context): String =
+ explained2(implicit ctx => em(args: _*))
}
}
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 80daa9681..4f01c43cf 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -975,7 +975,7 @@ object Denotations {
| $sym2: ${sym2.info};
|they are both defined in ${sym1.owner} but have matching signatures
| ${denot1.info} and
- | ${denot2.info}$fromWhere""".stripMargin,
+ | ${denot2.info}$fromWhere""",
denot2.info, denot2.info)
}
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 9d96f2b15..47ec541ab 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -669,9 +669,9 @@ object SymDenotations {
val cls = owner.enclosingSubClass
if (!cls.exists)
fail(
- s""" Access to protected $this not permitted because
+ i""" Access to protected $this not permitted because
| enclosing ${ctx.owner.enclosingClass.showLocated} is not a subclass of
- | ${owner.showLocated} where target is defined""".stripMargin)
+ | ${owner.showLocated} where target is defined""")
else if (
!( isType // allow accesses to types from arbitrary subclasses fixes #4737
|| pre.baseTypeRef(cls).exists // ??? why not use derivesFrom ???
@@ -679,9 +679,9 @@ object SymDenotations {
|| (owner is ModuleClass) // don't perform this check for static members
))
fail(
- s""" Access to protected ${symbol.show} not permitted because
+ i""" Access to protected ${symbol.show} not permitted because
| prefix type ${pre.widen.show} does not conform to
- | ${cls.showLocated} where the access takes place""".stripMargin)
+ | ${cls.showLocated} where the access takes place""")
else true
}
@@ -1933,10 +1933,10 @@ object SymDenotations {
else ("", "the signature")
val name = ctx.fresh.setSetting(ctx.settings.debugNames, true).nameString(denot.name)
ctx.error(
- s"""|bad symbolic reference. A signature$location
- |refers to $name in ${denot.owner.showKind} ${denot.owner.showFullName} which is not available.
- |It may be completely missing from the current classpath, or the version on
- |the classpath might be incompatible with the version used when compiling $src.""".stripMargin)
+ i"""bad symbolic reference. A signature$location
+ |refers to $name in ${denot.owner.showKind} ${denot.owner.showFullName} which is not available.
+ |It may be completely missing from the current classpath, or the version on
+ |the classpath might be incompatible with the version used when compiling $src.""")
if (ctx.debug) throw new Error()
initializeToDefaults(denot)
}
diff --git a/src/dotty/tools/dotc/core/SymbolLoaders.scala b/src/dotty/tools/dotc/core/SymbolLoaders.scala
index a62a88dfb..3f801bda5 100644
--- a/src/dotty/tools/dotc/core/SymbolLoaders.scala
+++ b/src/dotty/tools/dotc/core/SymbolLoaders.scala
@@ -70,8 +70,8 @@ class SymbolLoaders {
// require yjp.jar at runtime. See SI-2089.
if (ctx.settings.termConflict.isDefault)
throw new TypeError(
- sm"""$owner contains object and package with same name: $pname
- |one of them needs to be removed from classpath""")
+ i"""$owner contains object and package with same name: $pname
+ |one of them needs to be removed from classpath""")
else if (ctx.settings.termConflict.value == "package") {
ctx.warning(
s"Resolving package/object name conflict in favor of package ${preExisting.fullName}. The object will be inaccessible.")
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index d46ea6b0f..38b2c8bd6 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -510,6 +510,7 @@ object Symbols {
def toText(printer: Printer): Text = printer.toText(this)
def showLocated(implicit ctx: Context): String = ctx.locatedText(this).show
+ def showExtendedLocation(implicit ctx: Context): String = ctx.extendedLocationText(this).show
def showDcl(implicit ctx: Context): String = ctx.dclText(this).show
def showKind(implicit ctx: Context): String = ctx.kindString(this)
def showName(implicit ctx: Context): String = ctx.nameString(this)
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index d6ada7244..091999412 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -6,7 +6,6 @@ import Types._, Contexts._, Symbols._, Flags._, Names._, NameOps._, Denotations.
import Decorators._
import StdNames.{nme, tpnme}
import collection.mutable
-import printing.Disambiguation.disambiguated
import util.{Stats, DotClass, SimpleMap}
import config.Config
import config.Printers._
@@ -1469,7 +1468,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
/** Show subtype goal that led to an assertion failure */
def showGoal(tp1: Type, tp2: Type)(implicit ctx: Context) = {
- println(disambiguated(implicit ctx => s"assertion failure for ${tp1.show} <:< ${tp2.show}, frozen = $frozenConstraint"))
+ println(ex"assertion failure for $tp1 <:< $tp2, frozen = $frozenConstraint")
def explainPoly(tp: Type) = tp match {
case tp: PolyParam => ctx.echo(s"polyparam ${tp.show} found in ${tp.binder.show}")
case tp: TypeRef if tp.symbol.exists => ctx.echo(s"typeref ${tp.show} found in ${tp.symbol.owner.show}")
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 3e04e9c77..1bfd6eaee 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -1493,11 +1493,11 @@ object Types {
(sym.owner.derivesFrom(lastSymbol.owner) ||
selfTypeOf(sym).derivesFrom(lastSymbol.owner) ||
selfTypeOf(lastSymbol).derivesFrom(sym.owner))),
- s"""data race? overwriting symbol of type ${this.show},
- |long form = $this of class ${this.getClass},
+ i"""data race? overwriting symbol of type $this,
+ |long form = $toString of class $getClass,
|last sym id = ${lastSymbol.id}, new sym id = ${sym.id},
|last owner = ${lastSymbol.owner}, new owner = ${sym.owner},
- |period = ${ctx.phase} at run ${ctx.runId}""".stripMargin)
+ |period = ${ctx.phase} at run ${ctx.runId}""")
}
protected def sig: Signature = Signature.NotAMethod
@@ -3799,7 +3799,7 @@ object Types {
class MissingType(pre: Type, name: Name)(implicit ctx: Context) extends TypeError(
i"""cannot resolve reference to type $pre.$name
- |the classfile defining the type might be missing from the classpath${otherReason(pre)}""".stripMargin) {
+ |the classfile defining the type might be missing from the classpath${otherReason(pre)}""") {
if (ctx.debug) printStackTrace()
}
diff --git a/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
index a6d381693..4ea98f7c3 100644
--- a/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
+++ b/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
@@ -56,26 +56,21 @@ class ClassfileParser(
case e: RuntimeException =>
if (ctx.debug) e.printStackTrace()
throw new IOException(
- sm"""class file $classfile is broken, reading aborted with ${e.getClass}
- |${Option(e.getMessage).getOrElse("")}""")
+ i"""class file $classfile is broken, reading aborted with ${e.getClass}
+ |${Option(e.getMessage).getOrElse("")}""")
}
private def parseHeader(): Unit = {
val magic = in.nextInt
if (magic != JAVA_MAGIC)
- throw new IOException("class file '" + in.file + "' "
- + "has wrong magic number 0x" + toHexString(magic)
- + ", should be 0x" + toHexString(JAVA_MAGIC))
+ throw new IOException(s"class file '${in.file}' has wrong magic number 0x${toHexString(magic)}, should be 0x${toHexString(JAVA_MAGIC)}")
val minorVersion = in.nextChar.toInt
val majorVersion = in.nextChar.toInt
if ((majorVersion < JAVA_MAJOR_VERSION) ||
((majorVersion == JAVA_MAJOR_VERSION) &&
(minorVersion < JAVA_MINOR_VERSION)))
- throw new IOException("class file '" + in.file + "' "
- + "has unknown version "
- + majorVersion + "." + minorVersion
- + ", should be at least "
- + JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION)
+ throw new IOException(
+ s"class file '${in.file}' has unknown version $majorVersion.$minorVersion, should be at least $JAVA_MAJOR_VERSION.$JAVA_MINOR_VERSION")
}
/** Return the class symbol of the given name. */
@@ -817,12 +812,12 @@ class ClassfileParser(
getMember(owner, innerName.toTypeName)
}
assert(result ne NoSymbol,
- sm"""failure to resolve inner class:
- |externalName = $externalName,
- |outerName = $outerName,
- |innerName = $innerName
- |owner.fullName = ${owner.showFullName}
- |while parsing ${classfile}""")
+ i"""failure to resolve inner class:
+ |externalName = $externalName,
+ |outerName = $outerName,
+ |innerName = $innerName
+ |owner.fullName = ${owner.showFullName}
+ |while parsing ${classfile}""")
result
case None =>
diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
index 8ea4cecde..0d91e8cd6 100644
--- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
+++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
@@ -177,8 +177,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
protected def errorBadSignature(msg: String, original: Option[RuntimeException] = None)(implicit ctx: Context) = {
val ex = new BadSignature(
- sm"""error reading Scala signature of $classRoot from $source:
- |error occurred at position $readIndex: $msg""")
+ i"""error reading Scala signature of $classRoot from $source:
+ |error occurred at position $readIndex: $msg""")
if (ctx.debug || true) original.getOrElse(ex).printStackTrace() // temporarily enable printing of original failure signature to debug failing builds
throw ex
}
diff --git a/src/dotty/tools/dotc/printing/Disambiguation.scala b/src/dotty/tools/dotc/printing/Disambiguation.scala
deleted file mode 100644
index aa3fae2de..000000000
--- a/src/dotty/tools/dotc/printing/Disambiguation.scala
+++ /dev/null
@@ -1,86 +0,0 @@
-package dotty.tools.dotc
-package printing
-
-import core._
-import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Contexts._
-import collection.mutable
-import scala.annotation.switch
-
-object Disambiguation {
-
- private class State {
- var hasConflicts = false
- val symString = new mutable.HashMap[Symbol, String]
- val variants = new mutable.HashMap[String, mutable.ListBuffer[Symbol]]
- }
-
- def newPrinter: Context => RefinedPrinter = {
- val state = new State
- new Printer(state)(_)
- }
-
- private class Printer(state: State)(_ctx: Context) extends RefinedPrinter(_ctx) {
- import state._
-
- override def simpleNameString(sym: Symbol): String = {
- if ((sym is ModuleClass) && sym.sourceModule.exists) simpleNameString(sym.sourceModule)
- else symString.getOrElse(sym, recordedNameString(sym))
- }
-
- private def rawNameString(sym: Symbol) = super.simpleNameString(sym)
-
- private def recordedNameString(sym: Symbol): String = {
- val str = rawNameString(sym)
- val existing = variants.getOrElse(str, new mutable.ListBuffer[Symbol])
- // Dotty deviation: without a type parameter on ListBuffer, inference
- // will compute ListBuffer[Symbol] | ListBuffer[Nothing] as the type of "existing"
- // and then the assignment to variants below will fail.
- // We need to find a way to avoid such useless inferred types.
- if (!(existing contains sym)) {
- hasConflicts |= existing.nonEmpty
- variants(str) = (existing += sym)
- }
- str
- }
-
- def disambiguated(): Boolean = {
- val res = hasConflicts
- while (hasConflicts) disambiguate()
- res
- }
-
- private def qualifiers: Stream[String] =
- Stream("", "(some other)", "(some 3rd)") ++ (Stream.from(4) map (n => s"(some ${n}th)"))
-
- private def disambiguate(): Unit = {
- def update(sym: Symbol, str: String) = if (!(symString contains sym)) symString(sym) = str
- def disambiguated(sym: Symbol, owner: Symbol) = s"${rawNameString(sym)}(in ${simpleNameString(owner)})"
- hasConflicts = false
- for ((name, vs) <- variants.toList)
- if (vs.tail.nonEmpty) {
- for ((owner, syms) <- vs.groupBy(_.effectiveOwner)) {
- if (syms.tail.isEmpty) update(syms.head, disambiguated(syms.head, owner))
- else
- for {
- (kind, syms1) <- syms.groupBy(kindString)
- (sym, qual) <- syms1 zip qualifiers
- } {
- update(sym, s"$qual$kind ${disambiguated(sym, owner)}")
- }
- }
- }
- }
- }
-
- def disambiguated(op: Context => String)(implicit ctx: Context): String = {
- val dctx = ctx.printer match {
- case dp: Printer => ctx
- case _ => ctx.fresh.setPrinterFn(newPrinter)
- }
- val res = op(dctx)
- dctx.printer match {
- case dp: Printer if dp.disambiguated() => op(dctx)
- case _ => res
- }
- }
-}
diff --git a/src/dotty/tools/dotc/printing/Formatting.scala b/src/dotty/tools/dotc/printing/Formatting.scala
new file mode 100644
index 000000000..174d801d1
--- /dev/null
+++ b/src/dotty/tools/dotc/printing/Formatting.scala
@@ -0,0 +1,175 @@
+package dotty.tools.dotc
+package printing
+
+import core._
+import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Contexts._
+import collection.mutable
+import collection.Map
+import Decorators._
+import scala.annotation.switch
+import scala.util.control.NonFatal
+import reporting.Diagnostic
+
+object Formatting {
+
+ /** General purpose string formatter, with the following features:
+ *
+ * 1) On all Showables, `show` is called instead of `toString`
+ * 2) Exceptions raised by a `show` are handled by falling back to `toString`.
+ * 3) Sequences can be formatted using the desired separator between two `%` signs,
+ * eg `i"myList = (${myList}%, %)"`
+ * 4) Safe handling of multi-line margins. Left margins are skipped om the parts
+ * of the string context *before* inserting the arguments. That way, we guard
+ * against accidentally treating an interpolated value as a margin.
+ */
+ class StringFormatter(protected val sc: StringContext) {
+
+ protected def showArg(arg: Any)(implicit ctx: Context): String = arg match {
+ case arg: Showable =>
+ try arg.show(ctx.addMode(Mode.FutureDefsOK))
+ catch {
+ case NonFatal(ex) => s"(missing due to $ex)"
+ }
+ case _ => arg.toString
+ }
+
+ private def treatArg(arg: Any, suffix: String)(implicit ctx: Context): (Any, String) = arg match {
+ case arg: Seq[_] if suffix.nonEmpty && suffix.head == '%' =>
+ val (rawsep, rest) = suffix.tail.span(_ != '%')
+ val sep = StringContext.treatEscapes(rawsep)
+ if (rest.nonEmpty) (arg.map(showArg).mkString(sep), rest.tail)
+ else (arg, suffix)
+ case _ =>
+ (showArg(arg), suffix)
+ }
+
+ def assemble(args: Seq[Any])(implicit ctx: Context): String = {
+ def isLineBreak(c: Char) = c == '\n' || c == '\f' // compatible with StringLike#isLineBreak
+ def stripTrailingPart(s: String) = {
+ val (pre, post) = s.span(c => !isLineBreak(c))
+ pre ++ post.stripMargin
+ }
+ val (prefix, suffixes) = sc.parts.toList match {
+ case head :: tail => (head.stripMargin, tail map stripTrailingPart)
+ case Nil => ("", Nil)
+ }
+ val (args1, suffixes1) = (args, suffixes).zipped.map(treatArg(_, _)).unzip
+ new StringContext(prefix :: suffixes1.toList: _*).s(args1: _*)
+ }
+ }
+
+ /** The d string interpolator works like the i string interpolator, but marks nonsensical errors
+ * using `<nonsensical>...</nonsensical>` tags.
+ * Note: Instead of these tags, it would be nicer to return a data structure containing the message string
+ * and a boolean indicating whether the message is sensical, but then we cannot use string operations
+ * like concatenation, stripMargin etc on the values returned by d"...", and in the current error
+ * message composition methods, this is crucial.
+ */
+ class ErrorMessageFormatter(sc: StringContext) extends StringFormatter(sc) {
+ override protected def showArg(arg: Any)(implicit ctx: Context): String = {
+ def isSensical(arg: Any): Boolean = arg match {
+ case tpe: Type =>
+ tpe.exists && !tpe.isErroneous
+ case sym: Symbol if sym.isCompleted =>
+ sym.info != ErrorType && sym.info != TypeAlias(ErrorType) && sym.info.exists
+ case _ => true
+ }
+ val str = super.showArg(arg)
+ if (isSensical(arg)) str else Diagnostic.nonSensicalStartTag + str + Diagnostic.nonSensicalEndTag
+ }
+ }
+
+ private type Recorded = AnyRef /*Symbol | PolyParam*/
+
+ private class Seen extends mutable.HashMap[String, List[Recorded]] {
+
+ override def default(key: String) = Nil
+
+ def record(str: String, entry: Recorded): String = {
+ var alts = apply(str).dropWhile(entry ne _)
+ if (alts.isEmpty) {
+ alts = entry :: apply(str)
+ update(str, alts)
+ }
+ str + "'" * (alts.length - 1)
+ }
+ }
+
+ private class ExplainingPrinter(seen: Seen)(_ctx: Context) extends RefinedPrinter(_ctx) {
+ override def simpleNameString(sym: Symbol): String =
+ if ((sym is ModuleClass) && sym.sourceModule.exists) simpleNameString(sym.sourceModule)
+ else seen.record(super.simpleNameString(sym), sym)
+
+ override def polyParamNameString(param: PolyParam): String =
+ seen.record(super.polyParamNameString(param), param)
+ }
+
+ def explained2(op: Context => String)(implicit ctx: Context): String = {
+ val seen = new Seen
+ val explainCtx = 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))
+ }
+
+ def explanation(entry: Recorded): String = {
+ def boundStr(bound: Type, default: ClassSymbol, cmp: String) =
+ if (bound.isRef(default)) "" else i"$cmp $bound"
+
+ def boundsStr(bounds: TypeBounds): String = {
+ val lo = boundStr(bounds.lo, defn.NothingClass, ">:")
+ val hi = boundStr(bounds.hi, defn.AnyClass, "<:")
+ if (lo.isEmpty) hi
+ else if (hi.isEmpty) lo
+ else s"$lo and $hi"
+ }
+
+ def addendum(cat: String, info: Type)(implicit ctx: Context): String = info match {
+ case bounds @ TypeBounds(lo, hi) if bounds ne TypeBounds.empty =>
+ if (lo eq hi) i" which is an alias of $lo"
+ else i" with $cat ${boundsStr(bounds)}"
+ case _ =>
+ ""
+ }
+
+ entry match {
+ case param: PolyParam =>
+ s"is a type variable${addendum("constraint", ctx.typeComparer.bounds(param))}"
+ case sym: Symbol =>
+ val ownerStr =
+ if (!sym.exists) ""
+ else {
+ var owner = sym.effectiveOwner
+ if (owner.isLocalDummy) i" locally defined in ${owner.owner}"
+ else i" in $owner"
+ }
+ s"is a ${ctx.printer.kindString(sym)}${sym.showExtendedLocation}${addendum("bounds", sym.info)}"
+ }
+ }
+
+ def explanations(seen: Seen)(implicit ctx: Context): String = {
+ def needsExplanation(entry: Recorded) = entry match {
+ case param: PolyParam => ctx.typerState.constraint.contains(param)
+ case _ => false
+ }
+ val toExplain: List[(String, Recorded)] = seen.toList.flatMap {
+ case (str, entry :: Nil) =>
+ if (needsExplanation(entry)) (str, entry) :: Nil else Nil
+ case (str, entries) =>
+ entries.map(alt => (seen.record(str, alt), alt))
+ }.sortBy(_._1)
+ val explainParts = toExplain.map { case (str, entry) => (str, explanation(entry)) }
+ val explainLines = columnar(explainParts, " ")
+ if (explainLines.isEmpty) "" else i"\n\nwhere $explainLines%\n %\n"
+ }
+
+ op(explainCtx) ++ explanations(seen)
+ }
+
+ def columnar(parts: List[(String, String)], sep: String): List[String] = {
+ lazy val maxLen = parts.map(_._1.length).max
+ parts.map {
+ case (leader, trailer) =>
+ s"$leader${" " * (maxLen - leader.length)}$sep$trailer"
+ }
+ }
+}
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala
index acf4514ea..a92095d9b 100644
--- a/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -188,22 +188,22 @@ class PlainPrinter(_ctx: Context) extends Printer {
case tp: TypeLambda =>
typeLambdaText(tp.paramNames.map(_.toString), tp.variances, tp.paramBounds, tp.resultType)
case tp: PolyType =>
- def paramText(name: TypeName, bounds: TypeBounds) =
- toText(polyParamName(name)) ~ polyHash(tp) ~ toText(bounds)
+ def paramText(name: TypeName, bounds: TypeBounds): Text =
+ polyParamNameString(name) ~ polyHash(tp) ~ toText(bounds)
changePrec(GlobalPrec) {
"[" ~
Text((tp.paramNames, tp.paramBounds).zipped map paramText, ", ") ~
"]" ~ toText(tp.resultType)
}
- case PolyParam(pt, n) =>
- toText(polyParamName(pt.paramNames(n))) ~ polyHash(pt)
+ case tp: PolyParam =>
+ polyParamNameString(tp) ~ polyHash(tp.binder)
case AnnotatedType(tpe, annot) =>
toTextLocal(tpe) ~ " " ~ toText(annot)
case HKApply(tycon, args) =>
toTextLocal(tycon) ~ "[" ~ Text(args.map(argText), ", ") ~ "]"
case tp: TypeVar =>
if (tp.isInstantiated)
- toTextLocal(tp.instanceOpt) ~ "'" // debug for now, so that we can see where the TypeVars are.
+ toTextLocal(tp.instanceOpt) ~ "^" // debug for now, so that we can see where the TypeVars are.
else {
val constr = ctx.typerState.constraint
val bounds =
@@ -219,7 +219,9 @@ class PlainPrinter(_ctx: Context) extends Printer {
}
}.close
- protected def polyParamName(name: TypeName): TypeName = name
+ protected def polyParamNameString(name: TypeName): String = name.toString
+
+ protected def polyParamNameString(param: PolyParam): String = polyParamNameString(param.binder.paramNames(param.paramNum))
/** The name of the symbol without a unique id. Under refined printing,
* the decoded original name.
@@ -416,13 +418,33 @@ class PlainPrinter(_ctx: Context) extends Printer {
def locationText(sym: Symbol): Text =
if (!sym.exists) ""
else {
- val owns = sym.effectiveOwner
- if (owns.isClass && !isEmptyPrefix(owns)) " in " ~ toText(owns) else Text()
- }
+ val ownr = sym.effectiveOwner
+ if (ownr.isClass && !isEmptyPrefix(ownr)) " in " ~ toText(ownr) else Text()
+ }
def locatedText(sym: Symbol): Text =
(toText(sym) ~ locationText(sym)).close
+ def extendedLocationText(sym: Symbol): Text =
+ if (!sym.exists) ""
+ else {
+ def recur(ownr: Symbol, innerLocation: String): Text = {
+ def nextOuter(innerKind: String): Text =
+ recur(ownr.effectiveOwner,
+ if (!innerLocation.isEmpty) innerLocation
+ else s" in an anonymous $innerKind")
+ def showLocation(ownr: Symbol, where: String): Text =
+ innerLocation ~ " " ~ where ~ " " ~ toText(ownr)
+ if (ownr.isAnonymousClass) nextOuter("class")
+ else if (ownr.isAnonymousFunction) nextOuter("function")
+ else if (isEmptyPrefix(ownr)) ""
+ else if (ownr.isLocalDummy) showLocation(ownr.owner, "locally defined in")
+ else if (ownr.isTerm && !ownr.is(Module | Method)) showLocation(ownr, "in the initalizer of")
+ else showLocation(ownr, "in")
+ }
+ recur(sym.owner, "")
+ }
+
def toText(denot: Denotation): Text = toText(denot.symbol) ~ "/D"
@switch private def escapedChar(ch: Char): String = ch match {
diff --git a/src/dotty/tools/dotc/printing/Printer.scala b/src/dotty/tools/dotc/printing/Printer.scala
index 360874522..14b63012e 100644
--- a/src/dotty/tools/dotc/printing/Printer.scala
+++ b/src/dotty/tools/dotc/printing/Printer.scala
@@ -68,6 +68,9 @@ abstract class Printer {
/** Textual representation of symbol and its location */
def locatedText(sym: Symbol): Text
+ /** A description of sym's location */
+ def extendedLocationText(sym: Symbol): Text
+
/** Textual representation of denotation */
def toText(denot: Denotation): Text
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index ce063f06a..83f61c976 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -532,8 +532,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
def optText[T >: Untyped](tree: List[Tree[T]])(encl: Text => Text): Text =
if (tree.exists(!_.isEmpty)) encl(blockText(tree)) else ""
- override protected def polyParamName(name: TypeName): TypeName =
- name.unexpandedName
+ override protected def polyParamNameString(name: TypeName): String =
+ name.unexpandedName.toString
override protected def treatAsTypeParam(sym: Symbol): Boolean = sym is TypeParam
diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala
index bddfd2f68..b3d173a42 100644
--- a/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -79,11 +79,11 @@ trait Reporting { this: Context =>
if (reporter.isReportedFeatureUseSite(featureUseSite)) ""
else {
reporter.reportNewFeatureUseSite(featureUseSite)
- s"""|
- |This can be achieved by adding the import clause 'import $fqname'
- |or by setting the compiler option -language:$feature.
- |See the Scala docs for value $fqname for a discussion
- |why the feature $req be explicitly enabled.""".stripMargin
+ s"""
+ |This can be achieved by adding the import clause 'import $fqname'
+ |or by setting the compiler option -language:$feature.
+ |See the Scala docs for value $fqname for a discussion
+ |why the feature $req be explicitly enabled."""
}
}
diff --git a/src/dotty/tools/dotc/transform/CheckReentrant.scala b/src/dotty/tools/dotc/transform/CheckReentrant.scala
index 7e0e368b5..c9eefb22f 100644
--- a/src/dotty/tools/dotc/transform/CheckReentrant.scala
+++ b/src/dotty/tools/dotc/transform/CheckReentrant.scala
@@ -74,7 +74,7 @@ class CheckReentrant extends MiniPhaseTransform { thisTransformer =>
if (sym.is(Mutable)) {
ctx.error(
i"""possible data race involving globally reachable ${sym.showLocated}: ${sym.info}
- | use -Ylog:checkReentrant+ to find out more about why the variable is reachable.""".stripMargin)
+ | use -Ylog:checkReentrant+ to find out more about why the variable is reachable.""")
shared += sym
} else if (!sym.is(Method) || sym.is(Accessor | ParamAccessor)) {
scanning(sym) {
diff --git a/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/src/dotty/tools/dotc/transform/ExtensionMethods.scala
index 8d61cef42..62a21198d 100644
--- a/src/dotty/tools/dotc/transform/ExtensionMethods.scala
+++ b/src/dotty/tools/dotc/transform/ExtensionMethods.scala
@@ -215,19 +215,19 @@ object ExtensionMethods {
val candidates = extensionNames(imeth) map (companionInfo.decl(_).symbol) filter (_.exists)
val matching = candidates filter (c => FullParameterization.memberSignature(c.info) == imeth.signature)
assert(matching.nonEmpty,
- sm"""|no extension method found for:
- |
- | $imeth:${imeth.info.show} with signature ${imeth.signature}
- |
- | Candidates:
- |
- | ${candidates.map(c => c.name + ":" + c.info.show).mkString("\n")}
- |
- | Candidates (signatures normalized):
- |
- | ${candidates.map(c => c.name + ":" + c.info.signature + ":" + FullParameterization.memberSignature(c.info)).mkString("\n")}
- |
- | Eligible Names: ${extensionNames(imeth).mkString(",")}""")
+ i"""no extension method found for:
+ |
+ | $imeth:${imeth.info.show} with signature ${imeth.signature}
+ |
+ | Candidates:
+ |
+ | ${candidates.map(c => c.name + ":" + c.info.show).mkString("\n")}
+ |
+ | Candidates (signatures normalized):
+ |
+ | ${candidates.map(c => c.name + ":" + c.info.signature + ":" + FullParameterization.memberSignature(c.info)).mkString("\n")}
+ |
+ | Eligible Names: ${extensionNames(imeth).mkString(",")}""")
matching.head.asTerm
}
}
diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala
index 92d638be9..839189948 100644
--- a/src/dotty/tools/dotc/transform/PatternMatcher.scala
+++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala
@@ -1169,9 +1169,8 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
private def translatedAlts(alts: List[Tree]) = alts map (alt => rebindTo(alt).translate())
private def noStep() = step()()
- private def unsupportedPatternMsg = sm"""
- |unsupported pattern: ${tree.show} / $this (this is a scalac bug.)
- |""".trim
+ private def unsupportedPatternMsg =
+ i"unsupported pattern: ${tree.show} / $this (this is a scalac bug.)"
// example check: List[Int] <:< ::[Int]
private def extractorStep(): TranslationStep = {
diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala
index e8d6d03bf..4bcc90a41 100644
--- a/src/dotty/tools/dotc/transform/Pickler.scala
+++ b/src/dotty/tools/dotc/transform/Pickler.scala
@@ -89,8 +89,8 @@ class Pickler extends Phase {
if (previous != unpickled) {
output("before-pickling.txt", previous)
output("after-pickling.txt", unpickled)
- ctx.error(s"""pickling difference for ${cls.fullName} in ${cls.sourceFile}, for details:
+ ctx.error(i"""pickling difference for ${cls.fullName} in ${cls.sourceFile}, for details:
|
- | diff before-pickling.txt after-pickling.txt""".stripMargin)
+ | diff before-pickling.txt after-pickling.txt""")
}
}
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index f0a514e8c..c8f41b7fa 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -777,9 +777,9 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
maximizeType(unapplyArgType) match {
case Some(tvar) =>
def msg =
- d"""There is no best instantiation of pattern type $unapplyArgType
- |that makes it a subtype of selector type $selType.
- |Non-variant type variable ${tvar.origin} cannot be uniquely instantiated.""".stripMargin
+ ex"""There is no best instantiation of pattern type $unapplyArgType
+ |that makes it a subtype of selector type $selType.
+ |Non-variant type variable ${tvar.origin} cannot be uniquely instantiated."""
if (fromScala2x) {
// We can't issue an error here, because in Scala 2, ::[B] is invariant
// whereas List[+T] is covariant. According to the strict rule, a pattern
@@ -801,7 +801,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
unapp.println("Neither sub nor super")
unapp.println(TypeComparer.explained(implicit ctx => unapplyArgType <:< selType))
errorType(
- d"Pattern type $unapplyArgType is neither a subtype nor a supertype of selector type $selType",
+ ex"Pattern type $unapplyArgType is neither a subtype nor a supertype of selector type $selType",
tree.pos)
}
@@ -822,7 +822,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
case _ => args
}
if (argTypes.length != bunchedArgs.length) {
- ctx.error(d"wrong number of argument patterns for $qual; expected: ($argTypes%, %)", tree.pos)
+ ctx.error(em"wrong number of argument patterns for $qual; expected: ($argTypes%, %)", tree.pos)
argTypes = argTypes.take(args.length) ++
List.fill(argTypes.length - args.length)(WildcardType)
}
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index b1cceea88..d77520c77 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -25,7 +25,7 @@ import util.common._
import transform.SymUtils._
import Decorators._
import Uniques._
-import ErrorReporting.{err, errorType, DiagnosticString}
+import ErrorReporting.{err, errorType}
import config.Printers._
import collection.mutable
import SymDenotations.NoCompleter
@@ -40,11 +40,11 @@ object Checking {
def checkBounds(args: List[tpd.Tree], boundss: List[TypeBounds], instantiate: (Type, List[Type]) => Type)(implicit ctx: Context) = {
(args, boundss).zipped.foreach { (arg, bound) =>
if (!bound.isHK && arg.tpe.isHK)
- ctx.error(d"missing type parameter(s) for $arg", arg.pos)
+ ctx.error(ex"missing type parameter(s) for $arg", arg.pos)
}
for ((arg, which, bound) <- ctx.boundsViolations(args, boundss, instantiate))
ctx.error(
- d"Type argument ${arg.tpe} does not conform to $which bound $bound ${err.whyNoMatchStr(arg.tpe, bound)}",
+ ex"Type argument ${arg.tpe} does not conform to $which bound $bound ${err.whyNoMatchStr(arg.tpe, bound)}",
arg.pos)
}
@@ -65,7 +65,7 @@ object Checking {
tycon match {
case tycon: TypeLambda =>
ctx.errorOrMigrationWarning(
- d"unreducible application of higher-kinded type $tycon to wildcard arguments",
+ ex"unreducible application of higher-kinded type $tycon to wildcard arguments",
pos)
case _ =>
checkWildcardHKApply(tp.superType, pos)
@@ -117,14 +117,14 @@ object Checking {
case tref: TypeRef =>
val cls = tref.symbol
if (cls.is(AbstractOrTrait))
- ctx.error(d"$cls is abstract; cannot be instantiated", pos)
+ ctx.error(em"$cls is abstract; cannot be instantiated", pos)
if (!cls.is(Module)) {
// Create a synthetic singleton type instance, and check whether
// it conforms to the self type of the class as seen from that instance.
val stp = SkolemType(tp)
val selfType = tref.givenSelfType.asSeenFrom(stp, cls)
if (selfType.exists && !(stp <:< selfType))
- ctx.error(d"$tp does not conform to its self type $selfType; cannot be instantiated")
+ ctx.error(ex"$tp does not conform to its self type $selfType; cannot be instantiated")
}
case _ =>
}
@@ -133,7 +133,7 @@ object Checking {
def checkRealizable(tp: Type, pos: Position)(implicit ctx: Context): Unit = {
val rstatus = realizability(tp)
if (rstatus ne Realizable) {
- def msg = d"$tp is not a legal path\n since it${rstatus.msg}"
+ def msg = em"$tp is not a legal path\n since it${rstatus.msg}"
if (ctx.scala2Mode) ctx.migrationWarning(msg, pos) else ctx.error(msg, pos)
}
}
@@ -378,7 +378,7 @@ object Checking {
var tp1 =
if (tp.symbol.is(Private) &&
!accessBoundary(sym).isContainedIn(tp.symbol.owner)) {
- errors = (d"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}",
+ errors = (em"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}",
pos) :: errors
tp
}
@@ -422,20 +422,20 @@ trait Checking {
val sym = tree.tpe.termSymbol
// The check is avoided inside Java compilation units because it always fails
// on the singleton type Module.type.
- if ((sym is Package) || ((sym is JavaModule) && !ctx.compilationUnit.isJava)) ctx.error(d"$sym is not a value", tree.pos)
+ if ((sym is Package) || ((sym is JavaModule) && !ctx.compilationUnit.isJava)) ctx.error(em"$sym is not a value", tree.pos)
}
tree
}
/** Check that type `tp` is stable. */
def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit =
- if (!tp.isStable) ctx.error(d"$tp is not stable", pos)
+ if (!tp.isStable) ctx.error(ex"$tp is not stable", pos)
/** Check that all type members of `tp` have realizable bounds */
def checkRealizableBounds(tp: Type, pos: Position)(implicit ctx: Context): Unit = {
val rstatus = boundsRealizability(tp)
if (rstatus ne Realizable)
- ctx.error(i"$tp cannot be instantiated since it${rstatus.msg}", pos)
+ ctx.error(ex"$tp cannot be instantiated since it${rstatus.msg}", pos)
}
/** Check that `tp` is a class type.
@@ -447,11 +447,11 @@ trait Checking {
def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type =
tp.underlyingClassRef(refinementOK = false) match {
case tref: TypeRef =>
- if (traitReq && !(tref.symbol is Trait)) ctx.error(d"$tref is not a trait", pos)
+ if (traitReq && !(tref.symbol is Trait)) ctx.error(ex"$tref is not a trait", pos)
if (stablePrefixReq && ctx.phase <= ctx.refchecksPhase) checkStable(tref.prefix, pos)
tp
case _ =>
- ctx.error(d"$tp is not a class type", pos)
+ ctx.error(ex"$tp is not a class type", pos)
defn.ObjectType
}
@@ -475,7 +475,7 @@ trait Checking {
case tp: RecType =>
tp.rebind(tp.parent)
case tp @ TypeBounds(lo, hi) if !(lo <:< hi) =>
- ctx.error(d"no type exists between low bound $lo and high bound $hi$where", pos)
+ ctx.error(ex"no type exists between low bound $lo and high bound $hi$where", pos)
TypeAlias(hi)
case _ =>
tp
@@ -493,17 +493,17 @@ trait Checking {
typr.println(i"conflict? $decl $other")
if (decl.matches(other)) {
def doubleDefError(decl: Symbol, other: Symbol): Unit = {
- def ofType = if (decl.isType) "" else d": ${other.info}"
+ def ofType = if (decl.isType) "" else em": ${other.info}"
def explanation =
if (!decl.isRealMethod) ""
else "\n (the definitions have matching type signatures)"
- ctx.error(d"$decl is already defined as $other$ofType$explanation", decl.pos)
+ ctx.error(em"$decl is already defined as $other$ofType$explanation", decl.pos)
}
if (decl is Synthetic) doubleDefError(other, decl)
else doubleDefError(decl, other)
}
if ((decl is HasDefaultParams) && (other is HasDefaultParams)) {
- ctx.error(d"two or more overloaded variants of $decl have default arguments")
+ ctx.error(em"two or more overloaded variants of $decl have default arguments")
decl resetFlag HasDefaultParams
}
}
@@ -524,7 +524,7 @@ trait Checking {
ctx.error(i"$caller may not call constructor of $called", call.pos)
else if (called.is(Trait) && !caller.mixins.contains(called))
ctx.error(i"""$called is already implemented by super${caller.superClass},
- |its constructor cannot be called again""".stripMargin, call.pos)
+ |its constructor cannot be called again""", call.pos)
}
/** Check that `tpt` does not define a higher-kinded type */
@@ -532,7 +532,7 @@ trait Checking {
if (tpt.tpe.isHK && !ctx.compilationUnit.isJava) {
// be more lenient with missing type params in Java,
// needed to make pos/java-interop/t1196 work.
- errorTree(tpt, d"missing type parameter for ${tpt.tpe}")
+ errorTree(tpt, ex"missing type parameter for ${tpt.tpe}")
}
else tpt
}
diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala
index 6f7d427cb..ad84ff583 100644
--- a/src/dotty/tools/dotc/typer/ErrorReporting.scala
+++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala
@@ -9,8 +9,8 @@ import Types._, ProtoTypes._, Contexts._, Decorators._, Denotations._, Symbols._
import Applications._, Implicits._, Flags._
import util.Positions._
import reporting.Diagnostic
-import printing.Showable
-import printing.Disambiguation.disambiguated
+import printing.{Showable, RefinedPrinter}
+import scala.collection.mutable
import java.util.regex.Matcher.quoteReplacement
object ErrorReporting {
@@ -38,7 +38,7 @@ object ErrorReporting {
val treeSym = ctx.symOfContextTree(tree)
if (treeSym.exists && treeSym.name == cycleSym.name && treeSym.owner == cycleSym.owner) {
val result = if (cycleSym is Method) " result" else ""
- d"overloaded or recursive $cycleSym needs$result type"
+ em"overloaded or recursive $cycleSym needs$result type"
}
else errorMsg(msg, cx.outer)
case _ =>
@@ -48,6 +48,9 @@ object ErrorReporting {
errorMsg(ex.show, ctx)
}
+ def wrongNumberOfArgs(fntpe: Type, kind: String, expected: Int, pos: Position)(implicit ctx: Context) =
+ errorType(em"wrong number of ${kind}arguments for $fntpe, expected: $expected", pos)
+
class Errors(implicit ctx: Context) {
/** An explanatory note to be added to error messages
@@ -59,15 +62,15 @@ object ErrorReporting {
def expectedTypeStr(tp: Type): String = tp match {
case tp: PolyProto =>
- d"type arguments [${tp.targs}%, %] and ${expectedTypeStr(tp.resultType)}"
+ em"type arguments [${tp.targs}%, %] and ${expectedTypeStr(tp.resultType)}"
case tp: FunProto =>
val result = tp.resultType match {
case _: WildcardType | _: IgnoredProto => ""
- case tp => d" and expected result type $tp"
+ case tp => em" and expected result type $tp"
}
- d"arguments (${tp.typedArgs.tpes}%, %)$result"
+ em"arguments (${tp.typedArgs.tpes}%, %)$result"
case _ =>
- d"expected type $tp"
+ em"expected type $tp"
}
def anonymousTypeMemberStr(tpe: Type) = {
@@ -76,12 +79,12 @@ object ErrorReporting {
case _: PolyType | _: MethodType => "method"
case _ => "value of type"
}
- d"$kind $tpe"
+ em"$kind $tpe"
}
def overloadedAltsStr(alts: List[SingleDenotation]) =
- d"overloaded alternatives of ${denotStr(alts.head)} with types\n" +
- d" ${alts map (_.info)}%\n %"
+ em"overloaded alternatives of ${denotStr(alts.head)} with types\n" +
+ em" ${alts map (_.info)}%\n %"
def denotStr(denot: Denotation): String =
if (denot.isOverloaded) overloadedAltsStr(denot.alternatives)
@@ -97,9 +100,8 @@ object ErrorReporting {
def patternConstrStr(tree: Tree): String = ???
- def typeMismatch(tree: Tree, pt: Type, implicitFailure: SearchFailure = NoImplicitMatches): Tree = {
+ def typeMismatch(tree: Tree, pt: Type, implicitFailure: SearchFailure = NoImplicitMatches): Tree =
errorTree(tree, typeMismatchStr(normalize(tree.tpe, pt), pt) + implicitFailure.postscript)
- }
/** A subtype log explaining why `found` does not conform to `expected` */
def whyNoMatchStr(found: Type, expected: Type) =
@@ -108,28 +110,31 @@ object ErrorReporting {
else
""
- def typeMismatchStr(found: Type, expected: Type) = disambiguated { implicit ctx =>
- def infoStr = found match { // DEBUG
- case tp: TypeRef => s"with info ${tp.info} / ${tp.prefix.toString} / ${tp.prefix.dealias.toString}"
- case _ => ""
- }
+ def typeMismatchStr(found: Type, expected: Type) = {
// replace constrained polyparams and their typevars by their bounds where possible
- val reported = new TypeMap {
+ object reported extends TypeMap {
+ def setVariance(v: Int) = variance = v
+ val constraint = ctx.typerState.constraint
def apply(tp: Type): Type = tp match {
case tp: PolyParam =>
- val e = ctx.typerState.constraint.entry(tp)
- if (e.exists)
- if (variance > 0) e.bounds.hi
- else if (variance < 0) e.bounds.lo
- else tp
- else tp
+ constraint.entry(tp) match {
+ case bounds: TypeBounds =>
+ if (variance < 0) apply(constraint.fullUpperBound(tp))
+ else if (variance > 0) apply(constraint.fullLowerBound(tp))
+ else tp
+ case NoType => tp
+ case instType => apply(instType)
+ }
case tp: TypeVar => apply(tp.stripTypeVar)
case _ => mapOver(tp)
}
}
- d"""type mismatch:
- | found : $found
- | required: ${reported(expected)}""".stripMargin + whyNoMatchStr(found, expected)
+ val found1 = reported(found)
+ reported.setVariance(-1)
+ val expected1 = reported(expected)
+ ex"""type mismatch:
+ | found : $found1
+ | required: $expected1""" + whyNoMatchStr(found, expected)
}
/** Format `raw` implicitNotFound argument, replacing all
@@ -139,35 +144,11 @@ object ErrorReporting {
def implicitNotFoundString(raw: String, paramNames: List[String], args: List[Type]): String = {
def translate(name: String): Option[String] = {
val idx = paramNames.indexOf(name)
- if (idx >= 0) Some(quoteReplacement(args(idx).show)) else None
+ if (idx >= 0) Some(quoteReplacement(ex"${args(idx)}")) else None
}
"""\$\{\w*\}""".r.replaceSomeIn(raw, m => translate(m.matched.drop(2).init))
}
}
def err(implicit ctx: Context): Errors = new Errors
-
- /** The d string interpolator works like the i string interpolator, but marks nonsensical errors
- * using `<nonsensical>...</nonsensical>` tags.
- * Note: Instead of these tags, it would be nicer to return a data structure containing the message string
- * and a boolean indicating whether the message is sensical, but then we cannot use string operations
- * like concatenation, stripMargin etc on the values returned by d"...", and in the current error
- * message composition methods, this is crucial.
- */
- implicit class DiagnosticString(val sc: StringContext) extends AnyVal {
- def d(args: Any*)(implicit ctx: Context): String = {
- def isSensical(arg: Any): Boolean = arg match {
- case l: Seq[_] => l.forall(isSensical(_))
- case tpe: Type if tpe.isErroneous => false
- case NoType => false
- case sym: Symbol if sym.isCompleted =>
- sym.info != ErrorType && sym.info != TypeAlias(ErrorType) && sym.info != NoType
- case _ => true
- }
-
- val s = new StringInterpolators(sc).i(args : _*)
- if (args.forall(isSensical(_))) s
- else Diagnostic.nonSensicalStartTag + s + Diagnostic.nonSensicalEndTag
- }
- }
}
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index 1eba64e2e..0a3307140 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -217,8 +217,8 @@ object Implicits {
protected def pt: Type
protected def argument: tpd.Tree
protected def qualify(implicit ctx: Context) =
- if (argument.isEmpty) d"match type $pt"
- else d"convert from ${argument.tpe} to $pt"
+ if (argument.isEmpty) em"match type $pt"
+ else em"convert from ${argument.tpe} to $pt"
/** An explanation of the cause of the failure as a string */
def explanation(implicit ctx: Context): String
@@ -227,7 +227,7 @@ object Implicits {
/** An ambiguous implicits failure */
class AmbiguousImplicits(alt1: TermRef, alt2: TermRef, val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure {
def explanation(implicit ctx: Context): String =
- d"both ${err.refStr(alt1)} and ${err.refStr(alt2)} $qualify"
+ em"both ${err.refStr(alt1)} and ${err.refStr(alt2)} $qualify"
override def postscript(implicit ctx: Context) =
"\nNote that implicit conversions cannot be applied because they are ambiguous;" +
"\n " + explanation
@@ -235,17 +235,17 @@ object Implicits {
class NonMatchingImplicit(ref: TermRef, val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure {
def explanation(implicit ctx: Context): String =
- d"${err.refStr(ref)} does not $qualify"
+ em"${err.refStr(ref)} does not $qualify"
}
class ShadowedImplicit(ref: TermRef, shadowing: Type, val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure {
def explanation(implicit ctx: Context): String =
- d"${err.refStr(ref)} does $qualify but is shadowed by ${err.refStr(shadowing)}"
+ em"${err.refStr(ref)} does $qualify but is shadowed by ${err.refStr(shadowing)}"
}
class DivergingImplicit(ref: TermRef, val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure {
def explanation(implicit ctx: Context): String =
- d"${err.refStr(ref)} produces a diverging implicit search when trying to $qualify"
+ em"${err.refStr(ref)} produces a diverging implicit search when trying to $qualify"
}
class FailedImplicit(failures: List[ExplainedSearchFailure], val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure {
@@ -253,7 +253,9 @@ object Implicits {
if (failures.isEmpty) s" No implicit candidates were found that $qualify"
else " " + (failures map (_.explanation) mkString "\n ")
override def postscript(implicit ctx: Context): String =
- "\nImplicit search failure summary:\n" + explanation
+ i"""
+ |Implicit search failure summary:
+ |$explanation"""
}
}
@@ -456,7 +458,7 @@ trait Implicits { self: Typer =>
if (!arg.isEmpty) arg
else {
var msgFn = (where: String) =>
- d"no implicit argument of type $formal found for $where" + failure.postscript
+ em"no implicit argument of type $formal found for $where" + failure.postscript
for {
notFound <- formal.typeSymbol.getAnnotation(defn.ImplicitNotFoundAnnot)
Trees.Literal(Constant(raw: String)) <- notFound.argument(0)
@@ -568,7 +570,7 @@ trait Implicits { self: Typer =>
// Not clear whether we need to drop the `.widen` here. All tests pass with it in place, though.
assert(argument.isEmpty || argument.tpe.isValueType || argument.tpe.isInstanceOf[ExprType],
- d"found: $argument: ${argument.tpe}, expected: $pt")
+ em"found: $argument: ${argument.tpe}, expected: $pt")
/** The expected type for the searched implicit */
lazy val fullProto = implicitProto(pt, identity)
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index f917c233f..698f7e9a9 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -646,7 +646,7 @@ class Namer { typer: Typer =>
val pname = paramAccessor.name
def illegal(how: String): Unit = {
- ctx.error(d"Illegal override of public type parameter $pname in $parent$how", paramAccessor.pos)
+ ctx.error(em"Illegal override of public type parameter $pname in $parent$how", paramAccessor.pos)
ok = false
}
@@ -659,7 +659,7 @@ class Namer { typer: Typer =>
case TypeRef(pre, name1) if name1 == pname && (pre =:= cls.thisType) =>
// OK, parameter is passed on directly
case _ =>
- illegal(d".\nParameter is both redeclared and instantiated with $alias.")
+ illegal(em".\nParameter is both redeclared and instantiated with $alias.")
}
case _ => // OK, argument is not fully defined
}
@@ -832,7 +832,7 @@ class Namer { typer: Typer =>
// println(s"final inherited for $sym: ${inherited.toString}") !!!
// println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
def isInline = sym.is(Final, butNot = Method | Mutable)
-
+
// Widen rhs type and approximate `|' but keep ConstantTypes if
// definition is inline (i.e. final in Scala2).
def widenRhs(tp: Type): Type = tp.widenTermRefExpr match {
@@ -856,7 +856,7 @@ class Namer { typer: Typer =>
else {
if (sym is Implicit) {
val resStr = if (mdef.isInstanceOf[DefDef]) "result " else ""
- ctx.error(d"${resStr}type of implicit definition needs to be given explicitly", mdef.pos)
+ ctx.error(s"${resStr}type of implicit definition needs to be given explicitly", mdef.pos)
sym.resetFlag(Implicit)
}
lhsType orElse WildcardType
diff --git a/src/dotty/tools/dotc/typer/RefChecks.scala b/src/dotty/tools/dotc/typer/RefChecks.scala
index a654bb08f..2838866fd 100644
--- a/src/dotty/tools/dotc/typer/RefChecks.scala
+++ b/src/dotty/tools/dotc/typer/RefChecks.scala
@@ -81,14 +81,14 @@ object RefChecks {
def checkSelfConforms(other: TypeRef, category: String, relation: String) = {
val otherSelf = other.givenSelfType.asSeenFrom(cls.thisType, other.classSymbol)
if (otherSelf.exists && !(cinfo.selfType <:< otherSelf))
- ctx.error(d"$category: self type ${cinfo.selfType} of $cls does not conform to self type $otherSelf of $relation ${other.classSymbol}", cls.pos)
+ ctx.error(ex"$category: self type ${cinfo.selfType} of $cls does not conform to self type $otherSelf of $relation ${other.classSymbol}", cls.pos)
}
for (parent <- cinfo.classParents) {
val pclazz = parent.classSymbol
if (pclazz.is(Final))
- ctx.error(d"cannot extend final $pclazz", cls.pos)
+ ctx.error(em"cannot extend final $pclazz", cls.pos)
if (pclazz.is(Sealed) && pclazz.associatedFile != cls.associatedFile)
- ctx.error(d"cannot extend sealed $pclazz in different compilation unit", cls.pos)
+ ctx.error(em"cannot extend sealed $pclazz in different compilation unit", cls.pos)
checkSelfConforms(parent, "illegal inheritance", "parent")
}
for (reqd <- cinfo.givenSelfType.classSymbols)
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index c2b7b7101..ab151fb1d 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -171,13 +171,13 @@ trait TypeAssigner {
case sym :: Nil =>
if (sym.owner == pre.typeSymbol) sym.show else sym.showLocated
case _ =>
- d"none of the overloaded alternatives named $name"
+ em"none of the overloaded alternatives named $name"
}
val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else ""
val whyNot = new StringBuffer
alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot))
if (!tpe.isError)
- ctx.error(d"$what cannot be accessed as a member of $pre$where.$whyNot", pos)
+ ctx.error(ex"$what cannot be accessed as a member of $pre$where.$whyNot", pos)
ErrorType
}
}
@@ -205,10 +205,12 @@ trait TypeAssigner {
if (!site.isErroneous) {
def notAMember = d"${if (name.isTypeName) "type" else "value"} $name is not a member of $site"
ctx.error(
- if (name == nme.CONSTRUCTOR) d"$site does not have a constructor"
- else if (site.derivesFrom(defn.DynamicClass)) s"$notAMember\npossible cause: maybe a wrong Dynamic method signature?"
- else notAMember,
- pos)
+ if (name == nme.CONSTRUCTOR) ex"$site does not have a constructor"
+ else if (site.derivesFrom(defn.DynamicClass)) {
+ ex"$name is not a member of $site\n" +
+ "possible cause: maybe a wrong Dynamic method signature?"
+ }
+ else ex"$name is not a member of $site", pos)
}
ErrorType
}
@@ -283,7 +285,7 @@ trait TypeAssigner {
case p :: Nil =>
p
case Nil =>
- errorType(d"$mix does not name a parent class of $cls", tree.pos)
+ errorType(em"$mix does not name a parent class of $cls", tree.pos)
case p :: q :: _ =>
errorType("ambiguous parent class qualifier", tree.pos)
}
@@ -302,7 +304,7 @@ trait TypeAssigner {
val ownType = fn.tpe.widen match {
case fntpe @ MethodType(_, ptypes) =>
if (sameLength(ptypes, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes)
- else errorType(i"wrong number of parameters for ${fn.tpe}; expected: ${ptypes.length}", tree.pos)
+ else wrongNumberOfArgs(fn.tpe, "", ptypes.length, tree.pos)
case t =>
errorType(i"${err.exprStr(fn)} does not take parameters", tree.pos)
}
@@ -348,7 +350,7 @@ trait TypeAssigner {
else {
val argTypes = args.tpes
if (sameLength(argTypes, paramNames)|| ctx.phase.prev.relaxedTyping) pt.instantiate(argTypes)
- else errorType(d"wrong number of type parameters for ${fn.tpe}; expected: ${pt.paramNames.length}", tree.pos)
+ else wrongNumberOfArgs(fn.tpe, "type ", pt.paramNames.length, tree.pos)
}
case _ =>
errorType(i"${err.exprStr(fn)} does not take type parameters", tree.pos)
@@ -429,7 +431,7 @@ trait TypeAssigner {
val ownType =
if (hasNamedArg(args)) (tycon.tpe /: args)(refineNamed)
else if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes)
- else errorType(d"wrong number of type arguments for ${tycon.tpe}, should be ${tparams.length}", tree.pos)
+ else wrongNumberOfArgs(tycon.tpe, "type ", tparams.length, tree.pos)
tree.withType(ownType)
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index e982f9aa9..2b690ef51 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -134,8 +134,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
* or defined in <symbol>
*/
def bindingString(prec: Int, whereFound: Context, qualifier: String = "") =
- if (prec == wildImport || prec == namedImport) d"imported$qualifier by ${whereFound.importInfo}"
- else d"defined$qualifier in ${whereFound.owner}"
+ if (prec == wildImport || prec == namedImport) ex"imported$qualifier by ${whereFound.importInfo}"
+ else ex"defined$qualifier in ${whereFound.owner}"
/** Check that any previously found result from an inner context
* does properly shadow the new one from an outer context.
@@ -152,9 +152,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
else {
if (!previous.isError && !found.isError) {
error(
- d"""reference to $name is ambiguous;
- |it is both ${bindingString(newPrec, ctx, "")}
- |and ${bindingString(prevPrec, prevCtx, " subsequently")}""".stripMargin,
+ ex"""reference to $name is ambiguous;
+ |it is both ${bindingString(newPrec, ctx, "")}
+ |and ${bindingString(prevPrec, prevCtx, " subsequently")}""",
tree.pos)
}
previous
@@ -167,7 +167,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def checkUnambiguous(found: Type) = {
val other = namedImportRef(site, selectors.tail)
if (other.exists && found.exists && (found != other))
- error(d"reference to $name is ambiguous; it is imported twice in ${ctx.tree}",
+ error(em"reference to $name is ambiguous; it is imported twice in ${ctx.tree}",
tree.pos)
found
}
@@ -275,7 +275,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (rawType.exists)
ensureAccessible(rawType, superAccess = false, tree.pos)
else {
- error(d"not found: $kind$name", tree.pos)
+ error(em"not found: $kind$name", tree.pos)
ErrorType
}
@@ -304,10 +304,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
tree match {
case tree @ Select(qual, _) if !qual.tpe.isStable =>
val alt = typedSelect(tree, pt, Typed(qual, TypeTree(SkolemType(qual.tpe.widen))))
- typr.println(d"healed type: ${tree.tpe} --> $alt")
+ typr.println(i"healed type: ${tree.tpe} --> $alt")
alt.asInstanceOf[T]
case _ =>
- ctx.error(d"unsafe instantiation of type ${tree.tpe}", tree.pos)
+ ctx.error(ex"unsafe instantiation of type ${tree.tpe}", tree.pos)
tree
}
else tree
@@ -342,7 +342,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
convertToSelectFromType(tree.qualifier, tree.name) match {
case Some(sftt) => typedSelectFromTypeTree(sftt, pt)
- case _ => ctx.error(d"Could not convert $tree to a SelectFromTypeTree"); EmptyTree
+ case _ => ctx.error(em"Could not convert $tree to a SelectFromTypeTree"); EmptyTree
}
}
@@ -569,7 +569,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
ensureNoLocalRefs(tree1, pt, localSyms, forcedDefined = true)
} else
errorTree(tree,
- d"local definition of ${leaks.head.name} escapes as part of expression's type ${tree.tpe}"/*; full type: ${result.tpe.toString}"*/)
+ em"local definition of ${leaks.head.name} escapes as part of expression's type ${tree.tpe}"/*; full type: ${result.tpe.toString}"*/)
}
def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context) = track("typedIf") {
@@ -723,7 +723,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
pt match {
case SAMType(meth) if !defn.isFunctionType(pt) && mt <:< meth.info =>
if (!isFullyDefined(pt, ForceDegree.all))
- ctx.error(d"result type of closure is an underspecified SAM type $pt", tree.pos)
+ ctx.error(ex"result type of closure is an underspecified SAM type $pt", tree.pos)
TypeTree(pt)
case _ =>
if (!mt.isDependent) EmptyTree
@@ -802,7 +802,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
super.transform(tree.withType(elimWildcardSym(tree.tpe))) match {
case b: Bind =>
if (ctx.scope.lookup(b.name) == NoSymbol) ctx.enter(b.symbol)
- else ctx.error(d"duplicate pattern variable: ${b.name}", b.pos)
+ else ctx.error(em"duplicate pattern variable: ${b.name}", b.pos)
b.symbol.info = elimWildcardSym(b.symbol.info)
b
case t => t
@@ -854,7 +854,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val proto = returnProto(owner, cx.scope)
(from, proto)
}
- else (EmptyTree, errorType(d"$owner has return statement; needs result type", tree.pos))
+ else (EmptyTree, errorType(em"$owner has return statement; needs result type", tree.pos))
}
else enclMethInfo(cx.outer)
}
@@ -973,7 +973,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val tpt1 = typed(tree.tpt, AnyTypeConstructorProto)(ctx.retractMode(Mode.Pattern))
val tparams = tpt1.tpe.typeParams
if (tparams.isEmpty) {
- ctx.error(d"${tpt1.tpe} does not take type parameters", tree.pos)
+ ctx.error(ex"${tpt1.tpe} does not take type parameters", tree.pos)
tpt1
}
else {
@@ -982,7 +982,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (hasNamedArg(args)) typedNamedArgs(args)
else {
if (args.length != tparams.length) {
- ctx.error(d"wrong number of type arguments for ${tpt1.tpe}, should be ${tparams.length}", tree.pos)
+ wrongNumberOfArgs(tpt1.tpe, "type ", tparams.length, tree.pos)
args = args.take(tparams.length)
}
def typedArg(arg: untpd.Tree, tparam: TypeParamInfo) = {
@@ -1207,7 +1207,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case _ =>
// add synthetic class type
val first :: _ = ensureFirstIsClass(parents.tpes)
- TypeTree(checkFeasible(first, pos, d"\n in inferred parent $first")).withPos(pos) :: parents
+ TypeTree(checkFeasible(first, pos, em"\n in inferred parent $first")).withPos(pos) :: parents
}
/** If this is a real class, make sure its first parent is a
@@ -1239,7 +1239,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val packageContext =
if (pkg is Package) ctx.fresh.setOwner(pkg.moduleClass).setTree(tree)
else {
- ctx.error(d"$pkg is already defined, cannot be a package", tree.pos)
+ ctx.error(em"$pkg is already defined, cannot be a package", tree.pos)
ctx
}
val stats1 = typedStats(tree.stats, pkg.moduleClass)(packageContext)
@@ -1522,8 +1522,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def methodStr = err.refStr(methPart(tree).tpe)
def missingArgs = errorTree(tree,
- d"""missing arguments for $methodStr
- |follow this method with `_' if you want to treat it as a partially applied function""".stripMargin)
+ em"""missing arguments for $methodStr
+ |follow this method with `_' if you want to treat it as a partially applied function""")
def adaptOverloaded(ref: TermRef) = {
val altDenots = ref.denot.alternatives
@@ -1537,8 +1537,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case Nil =>
def noMatches =
errorTree(tree,
- d"""none of the ${err.overloadedAltsStr(altDenots)}
- |match $expectedStr""".stripMargin)
+ em"""none of the ${err.overloadedAltsStr(altDenots)}
+ |match $expectedStr""")
def hasEmptyParams(denot: SingleDenotation) = denot.info.paramTypess == ListOfNil
pt match {
case pt: FunProto =>
@@ -1553,8 +1553,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val remainingDenots = alts map (_.denot.asInstanceOf[SingleDenotation])
def all = if (remainingDenots.length == 2) "both" else "all"
errorTree(tree,
- d"""Ambiguous overload. The ${err.overloadedAltsStr(remainingDenots)}
- |$all match $expectedStr""".stripMargin)
+ em"""Ambiguous overload. The ${err.overloadedAltsStr(remainingDenots)}
+ |$all match $expectedStr""")
}
}
@@ -1581,7 +1581,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case Apply(_, _) => " more"
case _ => ""
}
- (_, _) => errorTree(tree, d"$methodStr does not take$more parameters")
+ (_, _) => errorTree(tree, em"$methodStr does not take$more parameters")
}
}
@@ -1630,7 +1630,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
val args = (wtp.paramNames, wtp.paramTypes).zipped map { (pname, formal) =>
def implicitArgError(msg: String => String) =
- errors += (() => msg(d"parameter $pname of $methodStr"))
+ errors += (() => msg(em"parameter $pname of $methodStr"))
inferImplicitArg(formal, implicitArgError, tree.pos.endPos)
}
if (errors.nonEmpty) {
diff --git a/tests/neg/i1430.scala b/tests/neg/i1430.scala
index 870780695..d988ba3f2 100644
--- a/tests/neg/i1430.scala
+++ b/tests/neg/i1430.scala
@@ -1,3 +1,4 @@
+class Inv[T](x: T)
object Test {
val x: List[String] = List(1) // error: found Int(1), expected: String
@@ -5,4 +6,29 @@ object Test {
val y: List[List[String]] = List(List(1)) // error: found Int(1), expected: String
val z: (List[String], List[Int]) = (List(1), List("a")) // error: found Int(1), expected: String // error: found String(a), expected: Int
+
+ val a: Inv[String] = new Inv(new Inv(1)) // error: found Inv[T], expected: String ... where T ...
+
+ val b: Inv[String] = new Inv(1) // error: found Int, expected: String
+
+ abstract class C {
+ type T
+ val x: T
+ val s: Unit = {
+ type T = String
+ var y: T = x // error
+ locally { def f() = {
+ new {
+ type T = Int
+ val z: T = y // error
+ }
+ Nil map { _ =>
+ type T = Int
+ val z: T = y // error
+ }
+ }
+ f()
+ }
+ }
+ }
}