Skip to content

Commit 4902c84

Browse files
committed
SI-8890 handle reference to overload with error
When buffering, we must report the ambiguity error to avoid a stack overflow. When the error refers to erroneous types/symbols, we don't report it directly to the user, because there will be an underlying error that's the root cause.
1 parent c038732 commit 4902c84

File tree

3 files changed

+40
-16
lines changed

3 files changed

+40
-16
lines changed

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

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -885,22 +885,31 @@ trait ContextErrors {
885885
val WrongNumber, NoParams, ArgsDoNotConform = Value
886886
}
887887

888-
private def issueAmbiguousTypeErrorUnlessErroneous(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String): Unit =
889-
if (!(pre.isErroneous || sym1.isErroneous || sym2.isErroneous)) {
890-
if (sym1.hasDefault && sym2.hasDefault && sym1.enclClass == sym2.enclClass) {
891-
val methodName = nme.defaultGetterToMethod(sym1.name)
892-
context.issueAmbiguousError(AmbiguousTypeError(sym1.enclClass.pos,
893-
"in "+ sym1.enclClass +", multiple overloaded alternatives of " + methodName +
894-
" define default arguments"))
895-
} else {
896-
context.issueAmbiguousError(AmbiguousTypeError(pos,
897-
("ambiguous reference to overloaded definition,\n" +
898-
"both " + sym1 + sym1.locationString + " of type " + pre.memberType(sym1) +
899-
"\nand " + sym2 + sym2.locationString + " of type " + pre.memberType(sym2) +
900-
"\nmatch " + rest)
901-
))
902-
}
903-
}
888+
private def issueAmbiguousTypeErrorUnlessErroneous(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String): Unit = {
889+
// To avoid stack overflows (SI-8890), we MUST (at least) report when either `validTargets` OR `ambiguousSuppressed`
890+
// More details:
891+
// If `!context.ambiguousErrors`, `reporter.issueAmbiguousError` (which `context.issueAmbiguousError` forwards to)
892+
// buffers ambiguous errors. In this case, to avoid looping, we must issue even if `!validTargets`. (TODO: why?)
893+
// When not buffering (and thus reporting to the user), we shouldn't issue unless `validTargets`,
894+
// otherwise we report two different errors that trace back to the same root cause,
895+
// and unless `validTargets`, we don't know for sure the ambiguity is real anyway.
896+
val validTargets = !(pre.isErroneous || sym1.isErroneous || sym2.isErroneous)
897+
val ambiguousBuffered = !context.ambiguousErrors
898+
if (validTargets || ambiguousBuffered)
899+
context.issueAmbiguousError(
900+
if (sym1.hasDefault && sym2.hasDefault && sym1.enclClass == sym2.enclClass) {
901+
val methodName = nme.defaultGetterToMethod(sym1.name)
902+
AmbiguousTypeError(sym1.enclClass.pos,
903+
s"in ${sym1.enclClass}, multiple overloaded alternatives of $methodName define default arguments")
904+
905+
} else {
906+
AmbiguousTypeError(pos,
907+
"ambiguous reference to overloaded definition,\n" +
908+
s"both ${sym1.fullLocationString} of type ${pre.memberType(sym1)}\n" +
909+
s"and ${sym2.fullLocationString} of type ${pre.memberType(sym2)}\n" +
910+
s"match $rest")
911+
})
912+
}
904913

905914
def AccessError(tree: Tree, sym: Symbol, ctx: Context, explanation: String): AbsTypeError =
906915
AccessError(tree, sym, ctx.enclClass.owner.thisType, ctx.enclClass.owner, explanation)

test/files/neg/t8890.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
t8890.scala:6: error: not found: type Str
2+
def bar(x: Str): Unit = ???
3+
^
4+
one error found

test/files/neg/t8890.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package foo
2+
3+
class A {
4+
/** The other */
5+
def bar(x: Int): Unit = ???
6+
def bar(x: Str): Unit = ???
7+
}
8+
9+
class B {
10+
(new A).bar(0)
11+
}

0 commit comments

Comments
 (0)