Skip to content

Commit 9ce109d

Browse files
jkcieslukWojciechMazur
authored andcommitted
bugfix: Choose correct signature is signatureHelp for overloaded methods
[Cherry-picked ab44759]
1 parent 0127f13 commit 9ce109d

File tree

3 files changed

+80
-14
lines changed

3 files changed

+80
-14
lines changed

compiler/src/dotty/tools/dotc/reporting/messages.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ extends NotFoundMsg(MissingIdentID) {
286286
}
287287
}
288288

289-
class TypeMismatch(found: Type, expected: Type, inTree: Option[untpd.Tree], addenda: => String*)(using Context)
289+
class TypeMismatch(val found: Type, expected: Type, inTree: Option[untpd.Tree], addenda: => String*)(using Context)
290290
extends TypeMismatchMsg(found, expected)(TypeMismatchID):
291291

292292
def msg(using Context) =

compiler/src/dotty/tools/dotc/util/Signatures.scala

+45-13
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ object Signatures {
221221
val funSymbol = fun.symbol
222222
val alternatives = if funSymbol.isLocalToBlock then List(funSymbol.denot) else
223223
funSymbol.owner.info.member(funSymbol.name).alternatives
224-
val alternativeIndex = alternatives.map(_.symbol).indexOf(funSymbol) max 0
224+
val alternativeIndex = bestAlternative(alternatives, params, paramssListIndex)
225225
(alternativeIndex, alternatives)
226226

227227
if alternativeIndex < alternatives.length then
@@ -660,24 +660,56 @@ object Signatures {
660660
case msg: NoMatchingOverload => msg.alternatives
661661
case _ => Nil
662662

663-
val userParamsTypes = params.map(_.tpe)
664663

665664
// Assign a score to each alternative (how many parameters are correct so far), and
666665
// use that to determine what is the current active signature.
666+
val alternativeIndex = bestAlternative(alternatives, params, paramssIndex)
667+
(alternativeIndex, alternatives)
668+
}
669+
670+
/**
671+
* Given a list of alternatives, and a list of parameters, returns the index of the best
672+
* alternative, i.e. the alternative that has the most formal parameters matching the given
673+
* arguments and the least number of formal parameters.
674+
*
675+
* @param alternatives The list of alternatives to inspect.
676+
* @param params The parameters that were given at the call site.
677+
* @param paramssIndex Index of paramss we are currently in.
678+
*
679+
* @return The index of the best alternative.
680+
*/
681+
private def bestAlternative(alternatives: List[SingleDenotation], params: List[tpd.Tree], paramssIndex: Int)(using Context): Int =
682+
val userParamsTypes = params.map(
683+
_.tpe match
684+
case e: PreviousErrorType =>
685+
/**
686+
* In case:
687+
* def foo(i: Int, s: String): Unit = ???
688+
* def foo(i: Boolean, s: Int, x: Double): Unit = ???
689+
* foo(false, @@)
690+
*
691+
* `false` has error type: `Required: Int, Found: Boolean`
692+
*/
693+
e.msg match
694+
case tm: TypeMismatch =>
695+
tm.found
696+
case _ => e
697+
case t => t
698+
)
667699
val alternativesScores = alternatives.map { alt =>
668700
val alreadyCurriedBonus = if (alt.symbol.paramSymss.length > paramssIndex) 1 else 0
669-
alt.info.stripPoly match
670-
case tpe: MethodType => alreadyCurriedBonus +
671-
userParamsTypes.zip(tpe.paramInfos).takeWhile{ case (t0, t1) => t0 <:< t1 }.size
672-
case _ => 0
701+
alt.info.stripPoly match
702+
case tpe: MethodType =>
703+
val score = alreadyCurriedBonus +
704+
userParamsTypes
705+
.zip(tpe.paramInfos)
706+
.takeWhile { case (t0, t1) =>t0 <:< t1 }
707+
.size
708+
(score, -tpe.paramInfos.length)
709+
case _ => (0, 0)
673710
}
674-
675-
val bestAlternative =
676-
if (alternativesScores.isEmpty) 0
677-
else alternativesScores.zipWithIndex.maxBy(_._1)._2
678-
679-
(bestAlternative, alternatives)
680-
}
711+
if (alternativesScores.isEmpty) 0
712+
else alternativesScores.zipWithIndex.maxBy(_._1)._2
681713
}
682714

683715

presentation-compiler/test/dotty/tools/pc/tests/signaturehelp/SignatureHelpSuite.scala

+34
Original file line numberDiff line numberDiff line change
@@ -1499,3 +1499,37 @@ class SignatureHelpSuite extends BaseSignatureHelpSuite:
14991499
| ^
15001500
|""".stripMargin
15011501
)
1502+
1503+
@Test def `correct-alternative` =
1504+
check(
1505+
"""
1506+
|object x {
1507+
| def foo(i: Int, s: String): Unit = ???
1508+
| def foo(i: Boolean, s: Int, x: Double): Unit = ???
1509+
|
1510+
| foo(false, @@)
1511+
|}
1512+
|""".stripMargin,
1513+
"""
1514+
|foo(i: Boolean, s: Int, x: Double): Unit
1515+
| ^^^^^^
1516+
|foo(i: Int, s: String): Unit
1517+
|""".stripMargin
1518+
)
1519+
1520+
@Test def `correct-alternative1` =
1521+
check(
1522+
"""
1523+
|object x {
1524+
| def foo(i: Boolean, s: String)(b: Int): Unit = ???
1525+
| def foo(i: Boolean, s: Int)(b: String): Unit = ???
1526+
|
1527+
| foo(false, 123)(@@)
1528+
|}
1529+
|""".stripMargin,
1530+
"""
1531+
|foo(i: Boolean, s: Int)(b: String): Unit
1532+
| ^^^^^^^^^
1533+
|foo(i: Boolean, s: String)(b: Int): Unit
1534+
|""".stripMargin
1535+
)

0 commit comments

Comments
 (0)