@@ -966,6 +966,53 @@ trait Applications extends Compatibility { self: Typer =>
966
966
def narrowByTypes (alts : List [TermRef ], argTypes : List [Type ], resultType : Type ): List [TermRef ] =
967
967
alts filter (isApplicable(_, argTypes, resultType))
968
968
969
+ /** Is `alt` a method or polytype whose result type after the first value parameter
970
+ * section conforms to the expected type `resultType`? If `resultType`
971
+ * is a `IgnoredProto`, pick the underlying type instead.
972
+ */
973
+ def resultConforms (alt : Type , resultType : Type )(implicit ctx : Context ): Boolean = resultType match {
974
+ case IgnoredProto (ignored) => resultConforms(alt, ignored)
975
+ case _ : ValueType =>
976
+ alt.widen match {
977
+ case tp : PolyType => resultConforms(constrained(tp).resultType, resultType)
978
+ case tp : MethodType => constrainResult(tp.resultType, resultType)
979
+ case _ => true
980
+ }
981
+ case _ => true
982
+ }
983
+
984
+ /** If the `chosen` alternative has a result type incompatible with the expected result
985
+ * type `pt`, run overloading resolution again on all alternatives that do match `pt`.
986
+ * If the latter succeeds with a single alternative, return it, otherwise
987
+ * fallback to `chosen`.
988
+ *
989
+ * Note this order of events is done for speed. One might be tempted to
990
+ * preselect alternatives by result type. But is slower, because it discriminates
991
+ * less. The idea is when searching for a best solution, as is the case in overloading
992
+ * resolution, we should first try criteria which are cheap and which have a high
993
+ * probability of pruning the search. result type comparisons are neither cheap nor
994
+ * do they prune much, on average.
995
+ */
996
+ def adaptByResult (alts : List [TermRef ], chosen : TermRef ) =
997
+ if (ctx.isAfterTyper) chosen
998
+ else {
999
+ def nestedCtx = ctx.fresh.setExploreTyperState
1000
+ pt match {
1001
+ case pt : FunProto if ! resultConforms(chosen, pt.resultType)(nestedCtx) =>
1002
+ alts.filter(alt =>
1003
+ (alt ne chosen) && resultConforms(alt, pt.resultType)(nestedCtx)) match {
1004
+ case Nil => chosen
1005
+ case alt2 :: Nil => alt2
1006
+ case alts2 =>
1007
+ resolveOverloaded(alts2, pt) match {
1008
+ case alt2 :: Nil => alt2
1009
+ case _ => chosen
1010
+ }
1011
+ }
1012
+ case _ => chosen
1013
+ }
1014
+ }
1015
+
969
1016
val candidates = pt match {
970
1017
case pt @ FunProto (args, resultType, _) =>
971
1018
val numArgs = args.length
@@ -1029,56 +1076,16 @@ trait Applications extends Compatibility { self: Typer =>
1029
1076
}
1030
1077
if (isDetermined(candidates)) candidates
1031
1078
else narrowMostSpecific(candidates) match {
1032
- case result @ (alt1 :: alt2 :: _) =>
1033
- // overload.println(i"ambiguous $alt1 $alt2")
1079
+ case Nil => Nil
1080
+ case alt :: Nil => adaptByResult(candidates, alt) :: Nil
1081
+ case alts =>
1082
+ // overload.println(i"ambiguous $alts%, %")
1034
1083
val deepPt = pt.deepenProto
1035
- if (deepPt ne pt) resolveOverloaded(alts, deepPt, targs)
1036
- else result
1037
- case result =>
1038
- result
1084
+ if (deepPt ne pt) resolveOverloaded(candidates, deepPt, targs)
1085
+ else alts
1039
1086
}
1040
1087
}
1041
1088
1042
- /** If the `chosen` alternative has a result type incompatible with the expected result
1043
- * type `pt`, run overloading resolution again on all alternatives that do match `pt`.
1044
- * If the latter succeeds with a single alternative, return it, otherwise
1045
- * fallback to `chosen`.
1046
- */
1047
- def adaptByResult (alts : List [TermRef ], chosen : TermRef , pt : Type )(implicit ctx : Context ) =
1048
- if (ctx.isAfterTyper) chosen
1049
- else {
1050
- def nestedCtx = ctx.fresh.setExploreTyperState
1051
- pt match {
1052
- case pt : FunProto if ! resultConforms(chosen, pt.resultType)(nestedCtx) =>
1053
- alts.filter(alt =>
1054
- (alt ne chosen) && resultConforms(alt, pt.resultType)(nestedCtx)) match {
1055
- case Nil => chosen
1056
- case alt2 :: Nil => alt2
1057
- case alts2 =>
1058
- resolveOverloaded(alts2, pt) match {
1059
- case alt2 :: Nil => alt2
1060
- case _ => chosen
1061
- }
1062
- }
1063
- case _ => chosen
1064
- }
1065
- }
1066
-
1067
- /** Is `alt` a method or polytype whose result type after the first value parameter
1068
- * section conforms to the expected type `resultType`? If `resultType`
1069
- * is a `IgnoredProto`, pick the underlying type instead.
1070
- */
1071
- private def resultConforms (alt : Type , resultType : Type )(implicit ctx : Context ): Boolean = resultType match {
1072
- case IgnoredProto (ignored) => resultConforms(alt, ignored)
1073
- case _ : ValueType =>
1074
- alt.widen match {
1075
- case tp : PolyType => resultConforms(constrained(tp).resultType, resultType)
1076
- case tp : MethodType => constrainResult(tp.resultType, resultType)
1077
- case _ => true
1078
- }
1079
- case _ => true
1080
- }
1081
-
1082
1089
private def harmonizeWith [T <: AnyRef ](ts : List [T ])(tpe : T => Type , adapt : (T , Type ) => T )(implicit ctx : Context ): List [T ] = {
1083
1090
def numericClasses (ts : List [T ], acc : Set [Symbol ]): Set [Symbol ] = ts match {
1084
1091
case t :: ts1 =>
0 commit comments