Skip to content

Commit 67491d6

Browse files
committed
Make applicability degrees more systematic
1 parent 9f5878d commit 67491d6

File tree

1 file changed

+34
-42
lines changed

1 file changed

+34
-42
lines changed

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 34 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -612,18 +612,24 @@ trait Applications extends Compatibility {
612612
}
613613
}
614614

615+
/** The degree to which an argument has to match a formal parameter */
616+
enum ArgMatch:
617+
case SubType // argument is a relaxed subtype of formal
618+
case Compatible // argument is compatible with formal
619+
case CompatibleCAP // capture-converted argument is compatible with formal
620+
615621
/** Subclass of Application for the cases where we are interested only
616622
* in a "can/cannot apply" answer, without needing to construct trees or
617623
* issue error messages.
618624
*/
619-
abstract class TestApplication[Arg](methRef: TermRef, funType: Type, args: List[Arg], resultType: Type, captureWild: Boolean)(using Context)
625+
abstract class TestApplication[Arg](methRef: TermRef, funType: Type, args: List[Arg], resultType: Type, argMatch: ArgMatch)(using Context)
620626
extends Application[Arg](methRef, funType, args, resultType) {
621627
type TypedArg = Arg
622628
type Result = Unit
623629

624630
def applyKind = ApplyKind.Regular
625631

626-
protected def argOK(arg: TypedArg, formal: Type): Boolean = argType(arg, formal) match {
632+
protected def argOK(arg: TypedArg, formal: Type): Boolean = argType(arg, formal) match
627633
case ref: TermRef if ref.denot.isOverloaded =>
628634
// in this case we could not resolve overloading because no alternative
629635
// matches expected type
@@ -633,15 +639,17 @@ trait Applications extends Compatibility {
633639
case SAMType(sam) => argtpe <:< sam.toFunctionType(isJava = formal.classSymbol.is(JavaDefined))
634640
case _ => false
635641
}
636-
isCompatible(argtpe, formal)
637-
|| ctx.mode.is(Mode.ImplicitsEnabled) && SAMargOK
638-
|| captureWild
639-
&& {
640-
val argtpe1 = argtpe.widen
641-
val captured = captureWildcards(argtpe1)
642-
(captured ne argtpe1) && (captured <:< formal.widenExpr)
643-
}
644-
}
642+
if argMatch == ArgMatch.SubType then
643+
argtpe relaxed_<:< formal.widenExpr
644+
else
645+
isCompatible(argtpe, formal)
646+
|| ctx.mode.is(Mode.ImplicitsEnabled) && SAMargOK
647+
|| argMatch == ArgMatch.CompatibleCAP
648+
&& {
649+
val argtpe1 = argtpe.widen
650+
val captured = captureWildcards(argtpe1)
651+
(captured ne argtpe1) && isCompatible(captured, formal.widenExpr)
652+
}
645653

646654
/** The type of the given argument */
647655
protected def argType(arg: Arg, formal: Type): Type
@@ -661,8 +669,8 @@ trait Applications extends Compatibility {
661669
/** Subclass of Application for applicability tests with type arguments and value
662670
* argument trees.
663671
*/
664-
class ApplicableToTrees(methRef: TermRef, args: List[Tree], resultType: Type, captureWild: Boolean)(using Context)
665-
extends TestApplication(methRef, methRef.widen, args, resultType, captureWild) {
672+
class ApplicableToTrees(methRef: TermRef, args: List[Tree], resultType: Type, argMatch: ArgMatch)(using Context)
673+
extends TestApplication(methRef, methRef.widen, args, resultType, argMatch) {
666674
def argType(arg: Tree, formal: Type): Type =
667675
if untpd.isContextualClosure(arg) && defn.isContextFunctionType(formal) then arg.tpe
668676
else normalize(arg.tpe, formal)
@@ -672,18 +680,9 @@ trait Applications extends Compatibility {
672680
def harmonizeArgs(args: List[Tree]): List[Tree] = harmonize(args)
673681
}
674682

675-
/** Subclass of Application for applicability tests with type arguments and value
676-
* argument trees.
677-
*/
678-
class ApplicableToTreesDirectly(methRef: TermRef, args: List[Tree], resultType: Type)(using Context)
679-
extends ApplicableToTrees(methRef, args, resultType, captureWild = false) {
680-
override def argOK(arg: TypedArg, formal: Type): Boolean =
681-
argType(arg, formal) relaxed_<:< formal.widenExpr
682-
}
683-
684683
/** Subclass of Application for applicability tests with value argument types. */
685-
class ApplicableToTypes(methRef: TermRef, args: List[Type], resultType: Type, captureWild: Boolean)(using Context)
686-
extends TestApplication(methRef, methRef, args, resultType, captureWild) {
684+
class ApplicableToTypes(methRef: TermRef, args: List[Type], resultType: Type, argMatch: ArgMatch)(using Context)
685+
extends TestApplication(methRef, methRef, args, resultType, argMatch) {
687686
def argType(arg: Type, formal: Type): Type = arg
688687
def treeToArg(arg: Tree): Type = arg.tpe
689688
def isVarArg(arg: Type): Boolean = arg.isRepeatedParam
@@ -1330,39 +1329,32 @@ trait Applications extends Compatibility {
13301329
/** Is given method reference applicable to argument trees `args`?
13311330
* @param resultType The expected result type of the application
13321331
*/
1333-
def isApplicableMethodRef(methRef: TermRef, args: List[Tree], resultType: Type, keepConstraint: Boolean, captureWild: Boolean)(using Context): Boolean = {
1332+
def isApplicableMethodRef(methRef: TermRef, args: List[Tree], resultType: Type, keepConstraint: Boolean, argMatch: ArgMatch)(using Context): Boolean = {
13341333
def isApp(using Context): Boolean =
1335-
new ApplicableToTrees(methRef, args, resultType, captureWild).success
1334+
new ApplicableToTrees(methRef, args, resultType, argMatch).success
13361335
if (keepConstraint) isApp else explore(isApp)
13371336
}
13381337

1339-
/** Is given method reference applicable to argument trees `args` without inferring views
1340-
* or capturing wildcards?
1341-
* @param resultType The expected result type of the application
1342-
*/
1343-
def isDirectlyApplicableMethodRef(methRef: TermRef, args: List[Tree], resultType: Type)(using Context): Boolean =
1344-
explore(new ApplicableToTreesDirectly(methRef, args, resultType).success)
1345-
13461338
/** Is given method reference applicable to argument types `args`?
13471339
* @param resultType The expected result type of the application
13481340
*/
1349-
def isApplicableMethodRef(methRef: TermRef, args: List[Type], resultType: Type, captureWild: Boolean)(using Context): Boolean =
1350-
explore(new ApplicableToTypes(methRef, args, resultType, captureWild).success)
1341+
def isApplicableMethodRef(methRef: TermRef, args: List[Type], resultType: Type, argMatch: ArgMatch)(using Context): Boolean =
1342+
explore(new ApplicableToTypes(methRef, args, resultType, argMatch).success)
13511343

13521344
/** Is given type applicable to argument trees `args`, possibly after inserting an `apply`?
13531345
* @param resultType The expected result type of the application
13541346
*/
13551347
def isApplicableType(tp: Type, args: List[Tree], resultType: Type, keepConstraint: Boolean)(using Context): Boolean =
13561348
onMethod(tp, args.nonEmpty) {
1357-
isApplicableMethodRef(_, args, resultType, keepConstraint, captureWild = false)
1349+
isApplicableMethodRef(_, args, resultType, keepConstraint, ArgMatch.Compatible)
13581350
}
13591351

13601352
/** Is given type applicable to argument types `args`, possibly after inserting an `apply`?
13611353
* @param resultType The expected result type of the application
13621354
*/
13631355
def isApplicableType(tp: Type, args: List[Type], resultType: Type)(using Context): Boolean =
13641356
onMethod(tp, args.nonEmpty) {
1365-
isApplicableMethodRef(_, args, resultType, captureWild = false)
1357+
isApplicableMethodRef(_, args, resultType, ArgMatch.Compatible)
13661358
}
13671359

13681360
private def onMethod(tp: Type, followApply: Boolean)(p: TermRef => Boolean)(using Context): Boolean = tp match {
@@ -1493,9 +1485,9 @@ trait Applications extends Compatibility {
14931485
|| {
14941486
if tp1.isVarArgsMethod then
14951487
tp2.isVarArgsMethod
1496-
&& isApplicableMethodRef(alt2, tp1.paramInfos.map(_.repeatedToSingle), WildcardType, captureWild = false)
1488+
&& isApplicableMethodRef(alt2, tp1.paramInfos.map(_.repeatedToSingle), WildcardType, ArgMatch.Compatible)
14971489
else
1498-
isApplicableMethodRef(alt2, tp1.paramInfos, WildcardType, captureWild = false)
1490+
isApplicableMethodRef(alt2, tp1.paramInfos, WildcardType, ArgMatch.Compatible)
14991491
}
15001492
case tp1: PolyType => // (2)
15011493
inContext(ctx.fresh.setExploreTyperState()) {
@@ -1804,7 +1796,7 @@ trait Applications extends Compatibility {
18041796
}
18051797

18061798
def narrowByTypes(alts: List[TermRef], argTypes: List[Type], resultType: Type): List[TermRef] =
1807-
alts.filterConserve(isApplicableMethodRef(_, argTypes, resultType, captureWild = true))
1799+
alts.filterConserve(isApplicableMethodRef(_, argTypes, resultType, ArgMatch.CompatibleCAP))
18081800

18091801
/** Normalization steps before checking arguments:
18101802
*
@@ -1873,11 +1865,11 @@ trait Applications extends Compatibility {
18731865

18741866
def narrowByTrees(alts: List[TermRef], args: List[Tree], resultType: Type): List[TermRef] = {
18751867
val alts2 = alts.filterConserve(alt =>
1876-
isDirectlyApplicableMethodRef(alt, args, resultType)
1868+
isApplicableMethodRef(alt, args, resultType, keepConstraint = false, ArgMatch.SubType)
18771869
)
18781870
if (alts2.isEmpty && !ctx.isAfterTyper)
18791871
alts.filterConserve(alt =>
1880-
isApplicableMethodRef(alt, args, resultType, keepConstraint = false, captureWild = true)
1872+
isApplicableMethodRef(alt, args, resultType, keepConstraint = false, ArgMatch.CompatibleCAP)
18811873
)
18821874
else
18831875
alts2

0 commit comments

Comments
 (0)