Skip to content

Commit

Permalink
remove heuristic, turn into a warning
Browse files Browse the repository at this point in the history
  • Loading branch information
lrytz committed Dec 14, 2022
1 parent 189fc85 commit c9ba59d
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 81 deletions.
2 changes: 0 additions & 2 deletions src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
Expand Up @@ -267,8 +267,6 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
val exposeEmptyPackage = BooleanSetting ("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly()
val Ydelambdafy = ChoiceSetting ("-Ydelambdafy", "strategy", "Strategy used for translating lambdas into JVM code.", List("inline", "method"), "method")

val legacyBinding = BooleanSetting("-Ylegacy-binding", "Observe legacy name binding preference for inherited member competing with local definition.")

// Allows a specialised jar to be written. For instance one that provides stable hashing of content, or customisation of the file storage
val YjarFactory = StringSetting ("-YjarFactory", "classname", "factory for jar files", classOf[DefaultJarFactory].getName)
val YaddBackendThreads = IntSetting ("-Ybackend-parallelism", "maximum worker threads for backend", 1, Some((1,16)), (x: String) => None )
Expand Down
60 changes: 28 additions & 32 deletions src/compiler/scala/tools/nsc/typechecker/Contexts.scala
Expand Up @@ -1362,8 +1362,28 @@ trait Contexts { self: Analyzer =>
LookupAmbiguous(s"it is imported twice in the same scope by\n$imp1\nand $imp2")
def ambiguousDefnAndImport(owner: Symbol, imp: ImportInfo) =
LookupAmbiguous(s"it is both defined in $owner and imported subsequently by \n$imp")
def ambiguousDefinitions(owner: Symbol, other: Symbol, addendum: String) =
LookupAmbiguous(s"it is both defined in $owner and available as ${other.fullLocationString}$addendum")
def ambiguousDefinitions(sym: Symbol, other: Symbol, otherFoundInSuper: Boolean, otherEnclClass: Symbol) = {
if (otherFoundInSuper) {
val enclDesc = if (otherEnclClass.isAnonymousClass) "anonymous class" else otherEnclClass.toString
val parent = otherEnclClass.parentSymbols.find(_.isNonBottomSubClass(other.owner)).getOrElse(NoSymbol)
val inherit = if (parent.exists && parent != other.owner) s", inherited through parent $parent" else ""
val message =
s"""it is both defined in the enclosing ${sym.owner} and available in the enclosing $enclDesc as $other (defined in ${other.ownsString}$inherit)
|Since 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
|To continue using the symbol from the superclass, write `this.${sym.name}`.""".stripMargin
if (currentRun.isScala3)
Some(LookupAmbiguous(message))
else {
// passing the message to `typedIdent` as attachment, we don't have the position here to report the warning
other.updateAttachment(
s"""reference to ${sym.name} is ambiguous;
|$message
|Or use `-Wconf:msg=legacy-binding:s` to silence this warning.""".stripMargin)
None
}
} else
Some(LookupAmbiguous(s"it is both defined in ${sym.owner} and available as ${other.fullLocationString}"))
}

def apply(thisContext: Context, name: Name)(qualifies: Symbol => Boolean): NameLookup = {
lookupError = null
Expand Down Expand Up @@ -1466,27 +1486,10 @@ trait Contexts { self: Analyzer =>
}
if (!defSym.exists) cx = cx.outer // push further outward
}
def forwardedClassParam = lastDef.isParamAccessor && {
val parentClass = lastDef.owner
val templateCtx = thisContext.nextEnclosing(c => c.tree.isInstanceOf[Template] && c.owner.isNonBottomSubClass(parentClass))
templateCtx.owner.superClass == parentClass && {
templateCtx.tree.asInstanceOf[Template].parents.headOption.collect {
case Apply(_, args) => args
} match {
case Some(args) =>
// named args? repeated args?
args.zip(parentClass.primaryConstructor.paramss.headOption.getOrElse(Nil)).exists {
case (arg: Ident, param) => param.name == lastDef.name && arg.symbol == defSym
case _ => false
}
case _ => false
}
}
}
if ((defSym.isAliasType || lastDef.isAliasType) && pre.memberType(defSym) =:= lastPre.memberType(lastDef))
defSym = NoSymbol
if (defSym.isStable && lastDef.isStable &&
(lastPre.memberType(lastDef).termSymbol == defSym || pre.memberType(defSym).termSymbol == lastDef || forwardedClassParam))
(lastPre.memberType(lastDef).termSymbol == defSym || pre.memberType(defSym).termSymbol == lastDef))
defSym = NoSymbol
foundInPrefix = inPrefix && defSym.exists
foundInSuper = foundInPrefix && defSym.owner != cx.owner
Expand Down Expand Up @@ -1524,7 +1527,7 @@ trait Contexts { self: Analyzer =>
* 1b) Definitions and declarations that are either inherited, or made
* available by a package clause and also defined in the same compilation unit
* as the reference to them, have the next highest precedence.
* (Same precedence as 1 under -Ylegacy-binding.)
* (Only in -Xsource:3, same precedence as 1 with a warning in Scala 2.)
* 2) Explicit imports have next highest precedence.
* 3) Wildcard imports have next highest precedence.
* 4) Definitions made available by a package clause, but not also defined in the same compilation unit
Expand Down Expand Up @@ -1588,7 +1591,7 @@ trait Contexts { self: Analyzer =>
// If the defSym is at 4, and there is a def at 1b in scope due to packaging, then the reference is ambiguous.
// Also if defSym is at 1b inherited, the reference can be rendered ambiguous by a def at 1a in scope.
val possiblyAmbiguousDefinition =
foundInSuper && cx.owner.isClass && !settings.legacyBinding.value ||
foundInSuper && cx.owner.isClass ||
foreignDefined && !defSym.hasPackageFlag
if (possiblyAmbiguousDefinition && !thisContext.unit.isJava) {
val defSym0 = defSym
Expand All @@ -1608,17 +1611,10 @@ trait Contexts { self: Analyzer =>
if (!done && (cx ne NoContext)) cx = cx.outer
}
if (defSym.exists && (defSym ne defSym0)) {
val addendum =
if (wasFoundInSuper)
s"""|
|Since 2.13.11, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
|If shadowing was intended, write `this.${defSym0.name}`.
|Or use `-Ylegacy-binding` to enable the previous behavior everywhere.""".stripMargin
else ""
val ambiguity =
if (preferDef) ambiguousDefinitions(owner = defSym.owner, defSym0, addendum)
else ambiguousDefnAndImport(owner = defSym.owner, imp1)
return ambiguity
if (preferDef) ambiguousDefinitions(defSym, defSym0, wasFoundInSuper, cx0.enclClass.owner)
else Some(ambiguousDefnAndImport(owner = defSym.owner, imp1))
if (ambiguity.nonEmpty) return ambiguity.get
}
defSym = defSym0
pre = pre0
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/scala/tools/nsc/typechecker/Typers.scala
Expand Up @@ -5501,6 +5501,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case sym => typed1(tree setSymbol sym, mode, pt)
}
case LookupSucceeded(qual, sym) =>
sym.getAndRemoveAttachment[String].foreach(w =>
runReporting.warning(tree.pos, w, WarningCategory.Other, context.owner))
(// this -> Foo.this
if (sym.isThisSym)
typed1(This(sym.owner) setPos tree.pos, mode, pt)
Expand Down
41 changes: 25 additions & 16 deletions test/files/neg/t11921-alias.check
@@ -1,22 +1,31 @@
t11921-alias.scala:16: error: reference to TT is ambiguous;
it is both defined in object O and available as type TT in class C
Since 2.13.11, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
If shadowing was intended, write `this.TT`.
Or use `-Ylegacy-binding` to enable the previous behavior everywhere.
t11921-alias.scala:18: warning: reference to TT is ambiguous;
it is both defined in the enclosing object O and available in the enclosing class D as type TT (defined in class C)
Since 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.TT`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def n(x: TT) = x // ambiguous
^
t11921-alias.scala:36: error: reference to c is ambiguous;
it is both defined in class B and available as value c in class A
Since 2.13.11, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
If shadowing was intended, write `this.c`.
Or use `-Ylegacy-binding` to enable the previous behavior everywhere.
t11921-alias.scala:38: warning: reference to c is ambiguous;
it is both defined in the enclosing class B and available in the enclosing anonymous class as value c (defined in class A)
Since 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.c`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def n = c // ambiguous
^
t11921-alias.scala:65: error: reference to name is ambiguous;
it is both defined in method m and available as value name in class A
Since 2.13.11, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
If shadowing was intended, write `this.name`.
Or use `-Ylegacy-binding` to enable the previous behavior everywhere.
t11921-alias.scala:57: warning: reference to name is ambiguous;
it is both defined in the enclosing method m and available in the enclosing anonymous class as value name (defined in class C)
Since 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.name`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(name)
^
3 errors
t11921-alias.scala:67: warning: reference to name is ambiguous;
it is both defined in the enclosing method m and available in the enclosing anonymous class as value name (defined in class A, inherited through parent class C)
Since 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.name`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(name)
^
error: No warnings can be incurred under -Werror.
4 warnings
1 error
2 changes: 2 additions & 0 deletions test/files/neg/t11921-alias.scala
@@ -1,3 +1,5 @@
// scalac: -Werror

object t1 {
class C[T] { type TT = T }
object O {
Expand Down
16 changes: 11 additions & 5 deletions test/files/neg/t11921.check
@@ -1,8 +1,14 @@
t11921.scala:6: error: reference to coll is ambiguous;
it is both defined in method lazyMap and available as method coll in trait Iterable
Since 2.13.11, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
If shadowing was intended, write `this.coll`.
Or use `-Ylegacy-binding` to enable the previous behavior everywhere.
t11921.scala:6: error: type mismatch;
found : A => B
required: B => B
def iterator = coll.iterator.map(f) // coll is ambiguous
^
t11921.scala:6: warning: reference to coll is ambiguous;
it is both defined in the enclosing method lazyMap and available in the enclosing anonymous class as method coll (defined in trait Iterable)
Since 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.coll`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def iterator = coll.iterator.map(f) // coll is ambiguous
^
1 warning
1 error
51 changes: 30 additions & 21 deletions test/files/neg/t11921b.check
@@ -1,29 +1,38 @@
t11921b.scala:11: error: reference to x is ambiguous;
it is both defined in object Test and available as value x in class C
Since 2.13.11, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
If shadowing was intended, write `this.x`.
Or use `-Ylegacy-binding` to enable the previous behavior everywhere.
t11921b.scala:11: warning: reference to x is ambiguous;
it is both defined in the enclosing object Test and available in the enclosing class D as value x (defined in class C)
Since 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.x`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(x) // error
^
t11921b.scala:15: error: reference to x is ambiguous;
it is both defined in object Test and available as value x in class C
Since 2.13.11, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
If shadowing was intended, write `this.x`.
Or use `-Ylegacy-binding` to enable the previous behavior everywhere.
t11921b.scala:15: warning: reference to x is ambiguous;
it is both defined in the enclosing object Test and available in the enclosing anonymous class as value x (defined in class C)
Since 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.x`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(x) // error
^
t11921b.scala:26: error: reference to y is ambiguous;
it is both defined in method c and available as value y in class D
Since 2.13.11, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
If shadowing was intended, write `this.y`.
Or use `-Ylegacy-binding` to enable the previous behavior everywhere.
t11921b.scala:26: warning: reference to y is ambiguous;
it is both defined in the enclosing method c and available in the enclosing anonymous class as value y (defined in class D)
Since 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.y`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(y) // error
^
t11921b.scala:38: error: reference to y is ambiguous;
it is both defined in method c and available as value y in class D
Since 2.13.11, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
If shadowing was intended, write `this.y`.
Or use `-Ylegacy-binding` to enable the previous behavior everywhere.
t11921b.scala:38: warning: reference to y is ambiguous;
it is both defined in the enclosing method c and available in the enclosing class E as value y (defined in class D)
Since 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.y`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(y) // error
^
4 errors
t11921b.scala:75: warning: reference to x is ambiguous;
it is both defined in the enclosing object Uhu and available in the enclosing class C as value x (defined in class A, inherited through parent class B)
Since 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.x`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def t = x // ambiguous, message mentions parent B
^
error: No warnings can be incurred under -Werror.
5 warnings
1 error
15 changes: 14 additions & 1 deletion test/files/neg/t11921b.scala
@@ -1,4 +1,4 @@

// scalac: -Werror

object test1 {

Expand Down Expand Up @@ -64,3 +64,16 @@ class C {
object D extends C {
println(global) // OK, since global is defined in package
}

object test5 {
class A { val x = 1 }
class B extends A
object Uhu {
val x = 2
class C extends B {
class Inner {
def t = x // ambiguous, message mentions parent B
}
}
}
}
2 changes: 1 addition & 1 deletion test/files/neg/t11921c.check
@@ -1,4 +1,4 @@
t11921c.scala:7: error: type mismatch;
t11921c.scala:6: error: type mismatch;
found : A => B
required: B => B
def iterator = coll.iterator.map(f) // coll is ambiguous
Expand Down
3 changes: 1 addition & 2 deletions test/files/neg/t11921c.scala
@@ -1,5 +1,4 @@

// scalac: -Ylegacy-binding
// scalac: -Wconf:msg=legacy-binding:s

class C {
def lazyMap[A, B](coll: Iterable[A], f: A => B) =
Expand Down
2 changes: 1 addition & 1 deletion test/files/pos/t11921b.scala
@@ -1,5 +1,5 @@

// scalac: -Werror -Ylegacy-binding
// scalac: -Werror -Wconf:msg=legacy-binding:s

object test1 {

Expand Down

0 comments on commit c9ba59d

Please sign in to comment.