Skip to content
Open
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
98 changes: 45 additions & 53 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4352,72 +4352,64 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
val allDenots = ref.denot.alternatives
if pt.isExtensionApplyProto then allDenots.filter(_.symbol.is(ExtensionMethod))
else allDenots
def altRef(alt: SingleDenotation) = TermRef(ref.prefix, ref.name, alt)
val alts = altDenots.map(altRef)

typr.println(i"adapt overloaded $ref with alternatives ${altDenots map (_.info)}%\n\n %")

/** Search for an alternative that does not take parameters.
* If there is one, return it, otherwise return the error tree.
*/
def tryParameterless(alts: List[TermRef])(error: => tpd.Tree): Tree =
def tryParameterless(error: => tpd.Tree): Tree =
alts.filter(_.info.isParameterless) match
case alt :: Nil => readaptSimplified(tree.withType(alt))
case _ =>
altDenots.find(_.info.paramInfoss == ListOfNil) match
case Some(alt) => readaptSimplified(tree.withType(alt.symbol.denot.termRef))
case Some(alt) => readaptSimplified(tree.withType(altRef(alt)))
case _ => error

def altRef(alt: SingleDenotation) = TermRef(ref.prefix, ref.name, alt)
val alts = altDenots.map(altRef)

resolveOverloaded(alts, pt) match
case alt :: Nil =>
readaptSimplified(tree.withType(alt))
case Nil =>
// If no alternative matches, there are still two ways to recover:
// 1. If context is an application, try to insert an apply or implicit
// 2. If context is not an application, pick a alternative that does
// not take parameters.

def errorNoMatch = errorTree(tree, NoMatchingOverload(altDenots, pt))

pt match
case pt: FunOrPolyProto if pt.applyKind != ApplyKind.Using =>
// insert apply or convert qualifier, but only for a regular application
tryInsertApplyOrImplicit(tree, pt, locked)(errorNoMatch)
case _ =>
tryParameterless(alts)(errorNoMatch)

case ambiAlts =>
// If there are ambiguous alternatives, and:
// 1. the types aren't erroneous
// 2. the expected type is not a function type
// 3. there exist a parameterless alternative
//
// Then, pick the parameterless alternative.
// See tests/pos/i10715-scala and tests/pos/i10715-java.

/** Constructs an "ambiguous overload" error */
def errorAmbiguous =
val remainingDenots = altDenots.filter(denot => ambiAlts.contains(altRef(denot)))
val addendum =
if ambiAlts.exists(!_.symbol.exists) then
i"""|
|
|Note: Overloaded definitions introduced by refinements cannot be resolved"""
else ""
errorTree(tree, AmbiguousOverload(tree, remainingDenots, pt, addendum))
end errorAmbiguous

if tree.tpe.isErroneous || pt.isErroneous then
tree.withType(UnspecifiedErrorType)
else
pt match
case _: FunProto =>
errorAmbiguous
case _ =>
tryParameterless(alts)(errorAmbiguous)

end match
case alt :: Nil =>
readaptSimplified(tree.withType(alt))
case Nil =>
// If no alternative matches, there are still two ways to recover:
// 1. If context is an application, try to insert an apply or implicit
// 2. If context is not an application, pick an alternative that does
// not take parameters.
def errorNoMatch = errorTree(tree, NoMatchingOverload(altDenots, pt))

pt match
case pt: FunOrPolyProto if pt.applyKind != ApplyKind.Using =>
// insert apply or convert qualifier, but only for a regular application
tryInsertApplyOrImplicit(tree, pt, locked)(errorNoMatch)
case _ =>
tryParameterless(errorNoMatch)
case ambiAlts =>
// If there are ambiguous alternatives, and:
// 1. the types aren't erroneous
// 2. the expected type is not a function type
// 3. there exists a parameterless alternative
//
// Then, pick the parameterless alternative. See tests/pos/i10715-*

/** Constructs an "ambiguous overload" error */
def errorAmbiguous =
val remainingDenots = altDenots.filter(denot => ambiAlts.contains(altRef(denot)))
val addendum =
if ambiAlts.exists(!_.symbol.exists) then
i"""|
|
|Note: Overloaded definitions introduced by refinements cannot be resolved"""
else ""
errorTree(tree, AmbiguousOverload(tree, remainingDenots, pt, addendum))

pt match
case pt if tree.tpe.isErroneous || pt.isErroneous =>
tree.withType(UnspecifiedErrorType)
case _: FunProto =>
errorAmbiguous
case _ =>
tryParameterless(errorAmbiguous)
end adaptOverloaded

def adaptToArgs(wtp: Type, pt: FunProto): Tree = wtp match {
Expand Down
12 changes: 12 additions & 0 deletions tests/pos/i24631/TestJava.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package example;

public abstract class TestJava<T> {
public abstract T create(String foo);

// Note that this is the method that's called from Scala code
public T create() { return create(""); }

public static class Concrete extends TestJava<String> {
@Override public String create(String foo) { return foo; }
}
}
2 changes: 2 additions & 0 deletions tests/pos/i24631/test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
val s = new example.TestJava.Concrete().create
val s2: String = s
11 changes: 11 additions & 0 deletions tests/pos/i24631b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//> using options -source:3.0-migration

abstract class C[A]:
def create(s: String): A
def create(): A = create("")

class D extends C[String]:
def create(s: String): String = s

val s = D().create
val s2: String = s
Loading