Skip to content

Commit

Permalink
Merge pull request #10462 from lrytz/ambiguous-default
Browse files Browse the repository at this point in the history
  • Loading branch information
SethTisue committed Jul 22, 2023
2 parents 7372170 + 9432f8c commit 2812948
Show file tree
Hide file tree
Showing 11 changed files with 58 additions and 55 deletions.
27 changes: 11 additions & 16 deletions src/compiler/scala/tools/nsc/typechecker/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1373,31 +1373,26 @@ 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(outer: Symbol, inherited: Symbol, foundInSuper: Boolean, currentClass: Symbol) =
def ambiguousDefinitions(outer: Symbol, inherited: Symbol, foundInSuper: Boolean, classOfInherited: Symbol, currentClass: Symbol) =
if (foundInSuper) {
if (inherited.isImplicit) None
else {
val outer1 = outer.alternatives.head
val inherited1 = inherited.alternatives.head
val classDesc = if (currentClass.isAnonymousClass) "anonymous class" else currentClass.toString
val parent = currentClass.parentSymbols.find(_.isNonBottomSubClass(inherited1.owner)).getOrElse(NoSymbol)
val classDesc = if (classOfInherited.isAnonymousClass) "anonymous class" else classOfInherited.toString
val parent = classOfInherited.parentSymbols.find(_.isNonBottomSubClass(inherited1.owner)).getOrElse(NoSymbol)
val inherit = if (parent.exists && parent != inherited1.owner) s", inherited through parent $parent" else ""
val fix = if (classOfInherited != currentClass) s"${classOfInherited.name}.this." else "this."
val message =
sm"""|it is both defined in the enclosing ${outer1.owner} and inherited in the enclosing $classDesc as $inherited1 (defined in ${inherited1.ownsString}$inherit)
|In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
|Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.${outer1.name}`."""
// For now (2.13.11), warn under Xsource:3. We'll consider warning by default (and erring in Xsource:3) in 2.13.12
if (currentRun.isScala3) {
// passing the message to `typedIdent` as attachment, we don't have the position here to report the warning
inherited.updateAttachment(LookupAmbiguityWarning(
sm"""|reference to ${outer1.name} is ambiguous;
|$message
|Or use `-Wconf:msg=legacy-binding:s` to silence this warning."""))
// Some(LookupAmbiguous(message)) // to make it an error in 2.13.12
None
} else
None
|Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `${fix}${outer1.name}`."""
inherited.updateAttachment(LookupAmbiguityWarning(
sm"""|reference to ${outer1.name} is ambiguous;
|$message
|Or use `-Wconf:msg=legacy-binding:s` to silence this warning.""", fix))
}
None
} else
Some(LookupAmbiguous(s"it is both defined in ${outer.owner} and available as ${inherited.fullLocationString}"))

Expand Down Expand Up @@ -1643,7 +1638,7 @@ trait Contexts { self: Analyzer =>
}
if (defSym.exists && (defSym ne defSym0)) {
val ambiguity =
if (preferDef) ambiguousDefinitions(defSym, defSym0, wasFoundInSuper, cx0.enclClass.owner)
if (preferDef) ambiguousDefinitions(defSym, defSym0, wasFoundInSuper, cx0.enclClass.owner, thisContext.enclClass.owner)
else Some(ambiguousDefnAndImport(owner = defSym.owner, imp1))
if (ambiguity.nonEmpty) return ambiguity.get
}
Expand Down
7 changes: 5 additions & 2 deletions src/compiler/scala/tools/nsc/typechecker/Typers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5568,8 +5568,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case sym => typed1(tree setSymbol sym, mode, pt)
}
case LookupSucceeded(qual, sym) =>
sym.getAndRemoveAttachment[LookupAmbiguityWarning].foreach(w =>
runReporting.warning(tree.pos, w.msg, WarningCategory.Other, context.owner))
sym.getAndRemoveAttachment[LookupAmbiguityWarning].foreach(w => {
val cat = if (currentRun.isScala3) WarningCategory.Scala3Migration else WarningCategory.Other
val fix = List(CodeAction("ambiguous reference", Some(w.msg), List(TextEdit(tree.pos.focusStart, w.fix))))
runReporting.warning(tree.pos, w.msg, cat, context.owner, fix)
})
(// this -> Foo.this
if (sym.isThisSym)
typed1(This(sym.owner) setPos tree.pos, mode, pt)
Expand Down
2 changes: 1 addition & 1 deletion src/reflect/scala/reflect/internal/StdAttachments.scala
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ trait StdAttachments {
/** For `val i = 42`, marks field as inferred so accessor (getter) can warn if implicit. */
case object FieldTypeInferred extends PlainAttachment

case class LookupAmbiguityWarning(msg: String) extends PlainAttachment
case class LookupAmbiguityWarning(msg: String, fix: String) extends PlainAttachment

/** Java sealed classes may be qualified with a permits clause specifying allowed subclasses. */
case class PermittedSubclasses(permits: List[Tree]) extends PlainAttachment
Expand Down
12 changes: 5 additions & 7 deletions test/files/neg/t11921-alias.check
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
t11921-alias.scala:18: warning: reference to TT is ambiguous;
t11921-alias.scala:18: error: reference to TT is ambiguous;
it is both defined in the enclosing object O and inherited in the enclosing class D as type TT (defined in class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.TT`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def n(x: TT) = x // ambiguous
^
t11921-alias.scala:38: warning: reference to c is ambiguous;
t11921-alias.scala:38: error: reference to c is ambiguous;
it is both defined in the enclosing class B and inherited in the enclosing anonymous class as value c (defined in class A)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.c`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def n = c // ambiguous
^
t11921-alias.scala:57: warning: reference to name is ambiguous;
t11921-alias.scala:57: error: reference to name is ambiguous;
it is both defined in the enclosing method m and inherited in the enclosing anonymous class as value name (defined in class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.name`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(name)
^
t11921-alias.scala:67: warning: reference to name is ambiguous;
t11921-alias.scala:67: error: reference to name is ambiguous;
it is both defined in the enclosing method m and inherited in the enclosing anonymous class as value name (defined in class A, inherited through parent class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, 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
4 errors
5 changes: 2 additions & 3 deletions test/files/neg/t11921.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ t11921.scala:6: error: type mismatch;
required: B => B
def iterator = coll.iterator.map(f) // coll is ambiguous
^
t11921.scala:6: warning: reference to coll is ambiguous;
t11921.scala:6: error: reference to coll is ambiguous;
it is both defined in the enclosing method lazyMap and inherited in the enclosing anonymous class as method coll (defined in trait Iterable)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, 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
2 errors
23 changes: 11 additions & 12 deletions test/files/neg/t11921b.check
Original file line number Diff line number Diff line change
@@ -1,61 +1,60 @@
t11921b.scala:135: error: could not find implicit value for parameter i: Int
def u = t // doesn't compile in Scala 2 (maybe there's a ticket for that)
^
t11921b.scala:11: warning: reference to x is ambiguous;
t11921b.scala:11: error: reference to x is ambiguous;
it is both defined in the enclosing object Test and inherited in the enclosing class D as value x (defined in class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.x`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(x) // error
^
t11921b.scala:15: warning: reference to x is ambiguous;
t11921b.scala:15: error: reference to x is ambiguous;
it is both defined in the enclosing object Test and inherited in the enclosing anonymous class as value x (defined in class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.x`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(x) // error
^
t11921b.scala:26: warning: reference to y is ambiguous;
t11921b.scala:26: error: reference to y is ambiguous;
it is both defined in the enclosing method c and inherited in the enclosing anonymous class as value y (defined in class D)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.y`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(y) // error
^
t11921b.scala:38: warning: reference to y is ambiguous;
t11921b.scala:38: error: reference to y is ambiguous;
it is both defined in the enclosing method c and inherited in the enclosing class E as value y (defined in class D)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.y`.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `E.this.y`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(y) // error
^
t11921b.scala:65: warning: reference to global is ambiguous;
t11921b.scala:65: error: reference to global is ambiguous;
it is both defined in the enclosing package <empty> and inherited in the enclosing object D as value global (defined in class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.global`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(global) // error
^
t11921b.scala:75: warning: reference to x is ambiguous;
t11921b.scala:75: error: reference to x is ambiguous;
it is both defined in the enclosing object Uhu and inherited in the enclosing class C as value x (defined in class A, inherited through parent class B)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.x`.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `C.this.x`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def t = x // ambiguous, message mentions parent B
^
t11921b.scala:89: warning: reference to a is ambiguous;
t11921b.scala:89: error: reference to a is ambiguous;
it is both defined in the enclosing class C and inherited in the enclosing trait J as method a (defined in trait I)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.a`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
val t = a // error
^
t11921b.scala:136: warning: reference to lo is ambiguous;
t11921b.scala:136: error: reference to lo is ambiguous;
it is both defined in the enclosing object test10 and inherited in the enclosing class C as value lo (defined in class P)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.lo`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def v = t(lo) // error
^
8 warnings
1 error
9 errors
7 changes: 3 additions & 4 deletions test/files/neg/t12816.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to
Applicable -Wconf / @nowarn filters for this fatal warning: msg=<part of the message>, cat=scala3-migration
package object p extends U {
^
t12816.scala:29: warning: reference to c is ambiguous;
t12816.scala:29: error: reference to c is ambiguous;
it is both defined in the enclosing package p and inherited in the enclosing trait RR as method c (defined in trait T)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.c`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def m3 = c // warn
^
t12816.scala:33: warning: reference to Z is ambiguous;
t12816.scala:33: error: reference to Z is ambiguous;
it is both defined in the enclosing package p and inherited in the enclosing trait RR as trait Z (defined in trait T)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.Z`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def n3: Z // warn
^
2 warnings
1 error
3 errors
7 changes: 3 additions & 4 deletions test/files/neg/t12816b.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to
Applicable -Wconf / @nowarn filters for this fatal warning: msg=<part of the message>, cat=scala3-migration
package object p extends U {
^
B.scala:19: warning: reference to c is ambiguous;
B.scala:19: error: reference to c is ambiguous;
it is both defined in the enclosing package p and inherited in the enclosing trait RR as method c (defined in trait T)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.c`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def m3 = c // warn
^
B.scala:23: warning: reference to Z is ambiguous;
B.scala:23: error: reference to Z is ambiguous;
it is both defined in the enclosing package p and inherited in the enclosing trait RR as trait Z (defined in trait T)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.Z`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def n3: Z // warn
^
2 warnings
1 error
3 errors
4 changes: 1 addition & 3 deletions test/files/neg/using-source3.check
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
using-source3.scala:14: warning: reference to f is ambiguous;
using-source3.scala:14: error: reference to f is ambiguous;
it is both defined in the enclosing class D and inherited in the enclosing class E as method f (defined in class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.f`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def g = f
^
error: No warnings can be incurred under -Werror.
1 warning
1 error
4 changes: 1 addition & 3 deletions test/files/neg/using-source3b.check
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
using-source3b.scala:13: warning: reference to f is ambiguous;
using-source3b.scala:13: error: reference to f is ambiguous;
it is both defined in the enclosing class D and inherited in the enclosing class E as method f (defined in class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.f`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def g = f
^
error: No warnings can be incurred under -Werror.
1 warning
1 error
15 changes: 15 additions & 0 deletions test/junit/scala/tools/nsc/reporters/AbstractCodeActionTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,21 @@ abstract class AbstractCodeActionTest extends BytecodeTesting {
""".stripMargin,
)

@Test def outerReference(): Unit = {
assertCodeSuggestion(
"""trait T { def f = 1 }
|object O1 { def f = 2; class C extends T { def t = f } }
|object O2 { def f = 2; class C extends T { object I { def t = f } } }
|object O3 { def f = 2; object C extends T { object I { def t = f } } }
|""".stripMargin,
"""trait T { def f = 1 }
|object O1 { def f = 2; class C extends T { def t = this.f } }
|object O2 { def f = 2; class C extends T { object I { def t = C.this.f } } }
|object O3 { def f = 2; object C extends T { object I { def t = C.this.f } } }
|""".stripMargin
)
}

def assertCodeSuggestion(original: String, expected: String): Unit = {
val run = compiler.newRun()
run.compileSources(compiler.global.newSourceFile(original) :: Nil)
Expand Down

0 comments on commit 2812948

Please sign in to comment.