From 2874096cc497b698e1e222814bb84e90acf7811c Mon Sep 17 00:00:00 2001 From: Enno Runne Date: Wed, 3 May 2017 23:11:22 +0200 Subject: [PATCH 1/2] Change Ambiguous Import error in Typer to case class --- .../reporting/diagnostic/ErrorMessageID.java | 1 + .../dotc/reporting/diagnostic/messages.scala | 35 +++++++++++++++++++ .../src/dotty/tools/dotc/typer/Typer.scala | 16 +-------- .../dotc/reporting/ErrorMessagesTests.scala | 30 ++++++++++++++++ 4 files changed, 67 insertions(+), 15 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java index 6ea168b99241..73bec87c01df 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -56,6 +56,7 @@ public enum ErrorMessageID { CyclicReferenceInvolvingID, CyclicReferenceInvolvingImplicitID, SuperQualMustBeParentID, + AmbiguousImportID, ; public int errorNumber() { diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index b3c49a333822..bd312ce2710f 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1223,4 +1223,39 @@ object messages { |Attempting to define a field in a method signature after a varargs field is an error. |""".stripMargin } + + case class AmbiguousImport(name: Names.Name, newPrec: Int, prevPrec: Int, prevCtx: Context)(implicit ctx: Context) + extends Message(AmbiguousImportID) { + + import typer.Typer.BindingPrec._ + + /** A string which explains how something was bound; Depending on `prec` this is either + * imported by + * or defined in + */ + private def bindingString(prec: Int, whereFound: Context, qualifier: String = "") = + if (isImportPrec(prec)) { + ex"""imported$qualifier by ${hl"${whereFound.importInfo}"}""" + } else + ex"""defined$qualifier in ${hl"${whereFound.owner.toString}"}""" + + + val msg = + s"""|reference to `${hl"$name"}` is ambiguous + |it is both ${bindingString(newPrec, ctx)} + |and ${bindingString(prevPrec, prevCtx, " subsequently")}""".stripMargin + + val kind = "Reference" + + val explanation = + hl"""|The compiler can't decide which of the possible choices you + |are referencing with $name. + |Note: + |- Definitions take precedence over imports + |- Named imports take precedence over wildcard imports + |- You may replace a name when imported using + | ${"import"} scala.{ $name => ${name.show + "Tick"} } + |""".stripMargin + } + } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 0b0ef92f06cc..5553c28eec8a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -140,16 +140,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def findRef(previous: Type, prevPrec: Int, prevCtx: Context)(implicit ctx: Context): Type = { import BindingPrec._ - /** A string which explains how something was bound; Depending on `prec` this is either - * imported by - * or defined in - */ - def bindingString(prec: Int, whereFound: Context, qualifier: String = "") = - if (prec == wildImport || prec == namedImport) { - ex"""imported$qualifier by ${hl"${whereFound.importInfo}"}""" - } else - ex"""defined$qualifier in ${hl"${whereFound.owner.toString}"}""" - /** Check that any previously found result from an inner context * does properly shadow the new one from an outer context. * @param found The newly found result @@ -170,11 +160,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } else { if (!scala2pkg && !previous.isError && !found.isError) { - error( - ex"""|reference to `$name` is ambiguous - |it is both ${bindingString(newPrec, ctx, "")} - |and ${bindingString(prevPrec, prevCtx, " subsequently")}""", - tree.pos) + error(AmbiguousImport(name, newPrec, prevPrec, prevCtx), tree.pos) } previous } diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index be160ac7fba0..b18959a8d451 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -329,4 +329,34 @@ class ErrorMessagesTests extends ErrorMessagesTest { assertEquals("B", qual.show) assertEquals("class C", cls.show) } + + @Test def ambiguousImport = + checkMessagesAfter("frontend") { + """ + |object A { + | class ToBeImported + |} + |object B { + | class ToBeImported + |} + |class C { + | import A.ToBeImported + | import B.ToBeImported + | + | val value: ToBeImported = ??? + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + val defn = ictx.definitions + + import typer.Typer.BindingPrec._ + + assertMessageCount(1, messages) + val AmbiguousImport(name, newPrec, prevPrec, prevCtx) :: Nil = messages + assertEquals("ToBeImported", name.show) + assertEquals(namedImport, newPrec) + assertEquals(namedImport, prevPrec) + } } From 3d8c79497b9213681ee1d5c537c49a3fcaa6893d Mon Sep 17 00:00:00 2001 From: Enno Runne Date: Mon, 8 May 2017 09:24:11 +0200 Subject: [PATCH 2/2] Remove stripMargin --- .../dotty/tools/dotc/reporting/diagnostic/messages.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index bd312ce2710f..0b6ce89c4a23 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1241,9 +1241,9 @@ object messages { val msg = - s"""|reference to `${hl"$name"}` is ambiguous + i"""|reference to `${hl"$name"}` is ambiguous |it is both ${bindingString(newPrec, ctx)} - |and ${bindingString(prevPrec, prevCtx, " subsequently")}""".stripMargin + |and ${bindingString(prevPrec, prevCtx, " subsequently")}""" val kind = "Reference" @@ -1255,7 +1255,7 @@ object messages { |- Named imports take precedence over wildcard imports |- You may replace a name when imported using | ${"import"} scala.{ $name => ${name.show + "Tick"} } - |""".stripMargin + |""" } }