Skip to content

Fix imported twice error messages #18102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
val rename: TermName = renamed match
case Ident(rename: TermName) => rename
case _ => name

def isUnimport = rename == nme.WILDCARD
}

case class Number(digits: String, kind: NumberKind)(implicit @constructorOnly src: SourceFile) extends TermTree
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
case JavaSymbolIsNotAValueID // errorNumber: 119
case DoubleDefinitionID // errorNumber: 120
case MatchCaseOnlyNullWarningID // errorNumber: 121
case ImportRenamedTwiceID // errorNumber: 122
case ImportedTwiceID // errorNumber: 122
case TypeTestAlwaysDivergesID // errorNumber: 123
case TermMemberNeedsNeedsResultTypeForImplicitSearchID // errorNumber: 124
case ClassCannotExtendEnumID // errorNumber: 125
Expand Down Expand Up @@ -198,6 +198,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
case NotConstantID // errorNumber: 182
case ClosureCannotHaveInternalParameterDependenciesID // errorNumber: 183
case MatchTypeNoCasesID // errorNumber: 184
case UnimportedAndImportedID // errorNumber: 185

def errorNumber = ordinal - 1

Expand Down
11 changes: 9 additions & 2 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2234,8 +2234,15 @@ extends NamingMsg(DoubleDefinitionID) {
def explain(using Context) = ""
}

class ImportRenamedTwice(ident: untpd.Ident)(using Context) extends SyntaxMsg(ImportRenamedTwiceID) {
def msg(using Context) = s"${ident.show} is renamed twice on the same import line."
class ImportedTwice(sel: Name)(using Context) extends SyntaxMsg(ImportedTwiceID) {
def msg(using Context) = s"${sel.show} is imported twice on the same import line."
def explain(using Context) = ""
}

class UnimportedAndImported(sel: Name, isImport: Boolean)(using Context) extends SyntaxMsg(UnimportedAndImportedID) {
def msg(using Context) =
val otherStr = if isImport then "and imported" else "twice"
s"${sel.show} is unimported $otherStr on the same import line."
def explain(using Context) = ""
}

Expand Down
14 changes: 10 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1511,17 +1511,23 @@ trait Checking {
* (2) Check that no import selector is renamed more than once.
*/
def checkImportSelectors(qualType: Type, selectors: List[untpd.ImportSelector])(using Context): Unit =
val seen = mutable.Set.empty[Name]
val originals = mutable.Set.empty[Name]
val targets = mutable.Set.empty[Name]

def checkIdent(sel: untpd.ImportSelector): Unit =
if sel.name != nme.ERROR
&& !qualType.member(sel.name).exists
&& !qualType.member(sel.name.toTypeName).exists
then
report.error(NotAMember(qualType, sel.name, "value"), sel.imported.srcPos)
if seen.contains(sel.name) then
report.error(ImportRenamedTwice(sel.imported), sel.imported.srcPos)
seen += sel.name
if sel.isUnimport then
if originals.contains(sel.name) then
report.error(UnimportedAndImported(sel.name, targets.contains(sel.name)), sel.imported.srcPos)
else
if targets.contains(sel.rename) then
report.error(ImportedTwice(sel.rename), sel.renamed.orElse(sel.imported).srcPos)
targets += sel.rename
originals += sel.name

if !ctx.compilationUnit.isJava then
for sel <- selectors do
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/ImportInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class ImportInfo(symf: Context ?=> Symbol,
else
if sel.rename != sel.name then
myExcluded = myExcluded.nn + sel.name
if sel.rename != nme.WILDCARD then
if !sel.isUnimport then
myForwardMapping = myForwardMapping.uncheckedNN.updated(sel.name, sel.rename)
myReverseMapping = myReverseMapping.uncheckedNN.updated(sel.rename, sel.name)

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1309,7 +1309,7 @@ class Namer { typer: Typer =>
if sel.isWildcard then
addWildcardForwarders(seen, sel.span)
else
if sel.rename != nme.WILDCARD then
if !sel.isUnimport then
addForwardersNamed(sel.name, sel.rename, sel.span)
addForwarders(sels1, sel.name :: seen)
case _ =>
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
fail(em"reference to `$name` is ambiguous; it is imported twice")
found

if selector.rename == termName && selector.rename != nme.WILDCARD then
if selector.rename == termName && !selector.isUnimport then
val memberName =
if selector.name == termName then name
else if name.isTypeName then selector.name.toTypeName
Expand Down
20 changes: 20 additions & 0 deletions tests/neg/i18082.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- [E122] Syntax Error: tests/neg/i18082.scala:5:23 --------------------------------------------------------------------
5 |import O.{a as b, b as b} // error
| ^
| b is imported twice on the same import line.
-- [E122] Syntax Error: tests/neg/i18082.scala:6:18 --------------------------------------------------------------------
6 |import O.{a as b, b} // error
| ^
| b is imported twice on the same import line.
-- [E122] Syntax Error: tests/neg/i18082.scala:7:13 --------------------------------------------------------------------
7 |import O.{a, a} // error
| ^
| a is imported twice on the same import line.
-- [E185] Syntax Error: tests/neg/i18082.scala:10:18 -------------------------------------------------------------------
10 |import O.{a as _, a as _} // error
| ^
| a is unimported twice on the same import line.
-- [E185] Syntax Error: tests/neg/i18082.scala:11:13 -------------------------------------------------------------------
11 |import O.{a, a as _} // error
| ^
| a is unimported and imported on the same import line.
12 changes: 12 additions & 0 deletions tests/neg/i18082.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
object O { val a = 1; val b = 2 }

import O.{a as b, a} // OK
import O.{a as b, b as a} // OK
import O.{a as b, b as b} // error
import O.{a as b, b} // error
import O.{a, a} // error

import O.{a as _, b as _} // ok
import O.{a as _, a as _} // error
import O.{a, a as _} // error

1 change: 0 additions & 1 deletion tests/neg/i3745c.scala

This file was deleted.