Skip to content

Commit 4ee4a02

Browse files
committed
Warning about changed precedence in imports when migrating to 2.13
1 parent 5ff747f commit 4ee4a02

7 files changed

Lines changed: 57 additions & 5 deletions

File tree

src/compiler/scala/tools/nsc/typechecker/Contexts.scala

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,14 @@ trait Contexts { self: Analyzer =>
12461246
def lookupImport(imp: ImportInfo, requireExplicit: Boolean) =
12471247
thisContext.importedAccessibleSymbol(imp, name, requireExplicit, record = true) filter qualifies
12481248

1249+
var importLookupFor213MigrationWarning = false
1250+
def depthOk213 = {
1251+
settings.isScala213 && !thisContext.unit.isJava && !cx(ContextMode.InPackageClauseName) && defSym.exists && isPackageOwnedInDifferentUnit(defSym) && {
1252+
importLookupFor213MigrationWarning = true
1253+
true
1254+
}
1255+
}
1256+
12491257
// Java: A single-type-import declaration d in a compilation unit c of package p
12501258
// that imports a type named n shadows, throughout c, the declarations of:
12511259
//
@@ -1259,17 +1267,29 @@ trait Contexts { self: Analyzer =>
12591267
// package clause in the same compilation unit where the definition occurs have
12601268
// highest precedence.
12611269
// 2) Explicit imports have next highest precedence.
1262-
def depthOk(imp: ImportInfo) = (
1263-
imp.depth > symbolDepth
1264-
|| (thisContext.unit.isJava && imp.isExplicitImport(name) && imp.depth == symbolDepth)
1265-
)
1270+
def depthOk(imp: ImportInfo) = {
1271+
imp.depth > symbolDepth ||
1272+
(thisContext.unit.isJava && imp.isExplicitImport(name) && imp.depth == symbolDepth) ||
1273+
depthOk213
1274+
}
12661275

12671276
while (!impSym.exists && importCursor.imp1Exists && depthOk(importCursor.imp1)) {
12681277
impSym = lookupImport(imp1, requireExplicit = false)
12691278
if (!impSym.exists)
12701279
importCursor.advanceImp1Imp2()
12711280
}
12721281

1282+
if (impSym.exists && importLookupFor213MigrationWarning) {
1283+
if (impSym != defSym && imp1.depth >= symbolDepth && !imp1.isExplicitImport(name)) {
1284+
val msg =
1285+
s"""This wildcard import imports ${impSym.fullName}, which is shadowed by ${defSym.fullName}.
1286+
|This is not according to the language specification and has changed in Scala 2.13, where ${impSym.fullName} takes precedence.
1287+
|To keep the same meaning in 2.12 and 2.13, un-import ${name} by adding `$name => _` to the import list.""".stripMargin
1288+
runReporting.warning(imp1.pos, msg, WarningCategory.Other, "")
1289+
}
1290+
impSym = NoSymbol
1291+
}
1292+
12731293
if (defSym.exists && impSym.exists) {
12741294
// imported symbols take precedence over package-owned symbols in different compilation units.
12751295
if (isPackageOwnedInDifferentUnit(defSym))
@@ -1706,6 +1726,8 @@ object ContextMode {
17061726
/** Were default arguments used? */
17071727
final val DiagUsedDefaults: ContextMode = 1 << 18
17081728

1729+
final val InPackageClauseName: ContextMode = 1 << 19
1730+
17091731
/** TODO: The "sticky modes" are EXPRmode, PATTERNmode, TYPEmode.
17101732
* To mimic the sticky mode behavior, when captain stickyfingers
17111733
* comes around we need to propagate those modes but forget the other

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5411,7 +5411,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
54115411

54125412
def typedPackageDef(pdef0: PackageDef) = {
54135413
val pdef = treeCopy.PackageDef(pdef0, pdef0.pid, pluginsEnterStats(this, pdef0.stats))
5414-
val pid1 = typedQualifier(pdef.pid).asInstanceOf[RefTree]
5414+
val pid1 = context.withMode(ContextMode.InPackageClauseName)(typedQualifier(pdef.pid).asInstanceOf[RefTree])
54155415
assert(sym.moduleClass ne NoSymbol, sym)
54165416
val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls))
54175417
.typedStats(pdef.stats, NoSymbol)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Test1.scala:4: warning: This wildcard import imports a.O, which is shadowed by b.O.
2+
This is not according to the language specification and has changed in Scala 2.13, where a.O takes precedence.
3+
To keep the same meaning in 2.12 and 2.13, un-import O by adding `O => _` to the import list.
4+
import a._
5+
^
6+
error: No warnings can be incurred under -Xfatal-warnings.
7+
one warning found
8+
one error found
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package a
2+
3+
object O { def a = 0 }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package b
2+
3+
object O { def b = 0 }
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// scalac: -Xsource:2.13 -Werror
2+
3+
package b
4+
import a._
5+
6+
class C {
7+
def t = O.b
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// scalac: -Xsource:2.13 -Werror
2+
3+
package b
4+
import b._ // no warning, imported b.O is the same as package member b.O
5+
6+
class D {
7+
def t = O.b
8+
}

0 commit comments

Comments
 (0)