@@ -396,12 +396,13 @@ object Implicits:
396
396
}
397
397
398
398
/** A successful search
399
- * @param tree The typed tree that needs to be inserted
400
- * @param ref The implicit reference that succeeded
401
- * @param level The level where the reference was found
399
+ * @param tree The typed tree that needs to be inserted
400
+ * @param ref The implicit reference that succeeded
401
+ * @param level The level where the reference was found
402
+ * @param isExtension Whether the result is an extension method application
402
403
* @param tstate The typer state to be committed if this alternative is chosen
403
404
*/
404
- case class SearchSuccess (tree : Tree , ref : TermRef , level : Int )(val tstate : TyperState , val gstate : GadtConstraint )
405
+ case class SearchSuccess (tree : Tree , ref : TermRef , level : Int , isExtension : Boolean = false )(val tstate : TyperState , val gstate : GadtConstraint )
405
406
extends SearchResult with RefAndLevel with Showable
406
407
407
408
/** A failed search */
@@ -491,12 +492,14 @@ object Implicits:
491
492
class AmbiguousImplicits (val alt1 : SearchSuccess , val alt2 : SearchSuccess , val expectedType : Type , val argument : Tree ) extends SearchFailureType {
492
493
def explanation (using Context ): String =
493
494
em " both ${err.refStr(alt1.ref)} and ${err.refStr(alt2.ref)} $qualify"
494
- override def whyNoConversion (using Context ): String = {
495
- val what = if (expectedType.isInstanceOf [SelectionProto ]) " extension methods" else " conversions"
496
- i """
497
- |Note that implicit $what cannot be applied because they are ambiguous;
498
- | $explanation"""
499
- }
495
+ override def whyNoConversion (using Context ): String =
496
+ if ! argument.isEmpty && argument.tpe.widen.isRef(defn.NothingClass ) then
497
+ " "
498
+ else
499
+ val what = if (expectedType.isInstanceOf [SelectionProto ]) " extension methods" else " conversions"
500
+ i """
501
+ |Note that implicit $what cannot be applied because they are ambiguous;
502
+ | $explanation"""
500
503
}
501
504
502
505
class MismatchedImplicit (ref : TermRef ,
@@ -802,12 +805,11 @@ trait Implicits:
802
805
val inferred = inferImplicit(adjust(to), from, from.span)
803
806
804
807
inferred match {
805
- case SearchSuccess (tree, ref, _)
806
- if isOldStyleFunctionConversion(ref.underlying) && ! tree.isInstanceOf [Applications .ExtMethodApply ] =>
807
- report.migrationWarning(
808
- i " The conversion ${ref} will not be applied implicitly here in Scala 3 because only implicit methods and instances of Conversion class will continue to work as implicit views. " ,
809
- from
810
- )
808
+ case SearchSuccess (_, ref, _, false ) if isOldStyleFunctionConversion(ref.underlying) =>
809
+ report.migrationWarning(
810
+ i " The conversion ${ref} will not be applied implicitly here in Scala 3 because only implicit methods and instances of Conversion class will continue to work as implicit views. " ,
811
+ from
812
+ )
811
813
case _ =>
812
814
}
813
815
@@ -829,7 +831,7 @@ trait Implicits:
829
831
*/
830
832
def inferImplicitArg (formal : Type , span : Span )(using Context ): Tree =
831
833
inferImplicit(formal, EmptyTree , span) match
832
- case SearchSuccess (arg, _, _) => arg
834
+ case SearchSuccess (arg, _, _, _ ) => arg
833
835
case fail @ SearchFailure (failed) =>
834
836
if fail.isAmbiguous then failed
835
837
else
@@ -937,7 +939,6 @@ trait Implicits:
937
939
case Select (qual, _) => apply(x, qual)
938
940
case Apply (fn, _) => apply(x, fn)
939
941
case TypeApply (fn, _) => apply(x, fn)
940
- case tree : Applications .AppProxy => apply(x, tree.app)
941
942
case _ : This => false
942
943
case _ => foldOver(x, tree)
943
944
}
@@ -1026,13 +1027,23 @@ trait Implicits:
1026
1027
pt, locked)
1027
1028
}
1028
1029
pt match
1029
- case selProto @ SelectionProto (selName : TermName , mbrType, _, _) if cand.isExtension =>
1030
+ case selProto @ SelectionProto (selName : TermName , mbrType, _, _) =>
1031
+
1030
1032
def tryExtension (using Context ) =
1031
1033
extMethodApply(untpd.Select (untpdGenerated, selName), argument, mbrType)
1032
- if cand.isConversion then
1034
+
1035
+ def tryConversionForSelection (using Context ) =
1036
+ val converted = tryConversion
1037
+ if ! ctx.reporter.hasErrors && ! selProto.isMatchedBy(converted.tpe) then
1038
+ // this check is needed since adapting relative to a `SelectionProto` can succeed
1039
+ // even if the term is not a subtype of the `SelectionProto`
1040
+ err.typeMismatch(converted, selProto)
1041
+ converted
1042
+
1043
+ if cand.isExtension && cand.isConversion then
1033
1044
val extensionCtx, conversionCtx = ctx.fresh.setNewTyperState()
1034
1045
val extensionResult = tryExtension(using extensionCtx)
1035
- val conversionResult = tryConversion (using conversionCtx)
1046
+ val conversionResult = tryConversionForSelection (using conversionCtx)
1036
1047
if ! extensionCtx.reporter.hasErrors then
1037
1048
extensionCtx.typerState.commit()
1038
1049
if ! conversionCtx.reporter.hasErrors then
@@ -1041,7 +1052,8 @@ trait Implicits:
1041
1052
else
1042
1053
conversionCtx.typerState.commit()
1043
1054
conversionResult
1044
- else tryExtension
1055
+ else if cand.isExtension then tryExtension
1056
+ else tryConversionForSelection
1045
1057
case _ =>
1046
1058
tryConversion
1047
1059
}
@@ -1060,10 +1072,7 @@ trait Implicits:
1060
1072
SearchFailure (adapted.withType(new MismatchedImplicit (ref, pt, argument)))
1061
1073
}
1062
1074
else
1063
- val returned =
1064
- if (cand.isExtension) Applications .ExtMethodApply (adapted)
1065
- else adapted
1066
- SearchSuccess (returned, ref, cand.level)(ctx.typerState, ctx.gadt)
1075
+ SearchSuccess (adapted, ref, cand.level, cand.isExtension)(ctx.typerState, ctx.gadt)
1067
1076
}
1068
1077
1069
1078
/** An implicit search; parameters as in `inferImplicit` */
@@ -1126,20 +1135,13 @@ trait Implicits:
1126
1135
case alt1 : SearchSuccess =>
1127
1136
var diff = compareAlternatives(alt1, alt2)
1128
1137
assert(diff <= 0 ) // diff > 0 candidates should already have been eliminated in `rank`
1129
- if diff == 0 then
1138
+ if diff == 0 && alt1.isExtension && alt2.isExtension then
1130
1139
// Fall back: if both results are extension method applications,
1131
1140
// compare the extension methods instead of their wrappers.
1132
- object extMethodApply :
1133
- def unapply (t : Tree ): Option [Type ] = t match
1134
- case t : Applications .ExtMethodApply => Some (methPart(stripApply(t.app)).tpe)
1135
- case _ => None
1136
- end extMethodApply
1137
-
1138
- (alt1.tree, alt2.tree) match
1139
- case (extMethodApply(ref1 : TermRef ), extMethodApply(ref2 : TermRef )) =>
1140
- diff = compare(ref1, ref2)
1141
+ def stripExtension (alt : SearchSuccess ) = methPart(stripApply(alt.tree)).tpe
1142
+ (stripExtension(alt1), stripExtension(alt2)) match
1143
+ case (ref1 : TermRef , ref2 : TermRef ) => diff = compare(ref1, ref2)
1141
1144
case _ =>
1142
-
1143
1145
if diff < 0 then alt2
1144
1146
else if diff > 0 then alt1
1145
1147
else SearchFailure (new AmbiguousImplicits (alt1, alt2, pt, argument), span)
@@ -1565,7 +1567,7 @@ final class SearchRoot extends SearchHistory:
1565
1567
else
1566
1568
result match {
1567
1569
case failure : SearchFailure => failure
1568
- case success @ SearchSuccess (tree, _, _) =>
1570
+ case success : SearchSuccess =>
1569
1571
import tpd ._
1570
1572
1571
1573
// We might have accumulated dictionary entries for by name implicit arguments
@@ -1588,7 +1590,7 @@ final class SearchRoot extends SearchHistory:
1588
1590
else prune(in.map(_._2) ++ trees, out, in ++ acc)
1589
1591
}
1590
1592
1591
- val pruned = prune(List (tree), implicitDictionary.map(_._2).toList, Nil )
1593
+ val pruned = prune(List (success. tree), implicitDictionary.map(_._2).toList, Nil )
1592
1594
myImplicitDictionary = null
1593
1595
if (pruned.isEmpty) result
1594
1596
else if (pruned.exists(_._2 == EmptyTree )) NoMatchingImplicitsFailure
@@ -1645,7 +1647,7 @@ final class SearchRoot extends SearchHistory:
1645
1647
case tree => tree
1646
1648
})
1647
1649
1648
- val res = resMap(tree)
1650
+ val res = resMap(success. tree)
1649
1651
1650
1652
val blk = Block (classDef :: inst :: Nil , res).withSpan(span)
1651
1653
0 commit comments