@@ -1089,7 +1089,10 @@ trait Applications extends Compatibility { self: Typer =>
1089
1089
val alts2 = narrowByShapes(alts1)
1090
1090
// ctx.log(i"narrowed by shape: ${alts1.map(_.symbol.showDcl)}%, %")
1091
1091
if (isDetermined(alts2)) alts2
1092
- else narrowByTrees(alts2, pt.typedArgs, resultType)
1092
+ else {
1093
+ pretypeArgs(alts2, pt)
1094
+ narrowByTrees(alts2, pt.typedArgs, resultType)
1095
+ }
1093
1096
}
1094
1097
1095
1098
case pt @ PolyProto (targs, pt1) =>
@@ -1122,6 +1125,69 @@ trait Applications extends Compatibility { self: Typer =>
1122
1125
}
1123
1126
}
1124
1127
1128
+ /** Try to typecheck any arguments in `pt` that are function values missing a
1129
+ * parameter type. The expected type for these arguments is the lub of the
1130
+ * corresponding formal parameter types of all alternatives. Type variables
1131
+ * in formal parameter types are replaced by wildcards. The result of the
1132
+ * typecheck is stored in `pt`, to be retrieved when its `typedArgs` are selected.
1133
+ * The benefit of doing this is to allow idioms like this:
1134
+ *
1135
+ * def map(f: Char => Char): String = ???
1136
+ * def map[U](f: Char => U): Seq[U] = ???
1137
+ * map(x => x.toUpper)
1138
+ *
1139
+ * Without `pretypeArgs` we'd get a "missing parameter type" error for `x`.
1140
+ * With `pretypeArgs`, we use the union of the two formal parameter types
1141
+ * `Char => Char` and `Char => ?` as the expected type of the closure `x => x.toUpper`.
1142
+ * That union is `Char => Char`, so we have an expected parameter type `Char`
1143
+ * for `x`, and the code typechecks.
1144
+ */
1145
+ private def pretypeArgs (alts : List [TermRef ], pt : FunProto )(implicit ctx : Context ): Unit = {
1146
+ def recur (altFormals : List [List [Type ]], args : List [untpd.Tree ]): Unit = args match {
1147
+ case arg :: args1 if ! altFormals.exists(_.isEmpty) =>
1148
+ def isUnknownParamType (t : untpd.Tree ) = t match {
1149
+ case ValDef (_, tpt, _) => tpt.isEmpty
1150
+ case _ => false
1151
+ }
1152
+ arg match {
1153
+ case arg : untpd.Function if arg.args.exists(isUnknownParamType) =>
1154
+ def isUniform [T ](xs : List [T ])(p : (T , T ) => Boolean ) = xs.forall(p(_, xs.head))
1155
+ val formalsForArg : List [Type ] = altFormals.map(_.head)
1156
+ // For alternatives alt_1, ..., alt_n, test whether formal types for current argument are of the form
1157
+ // (p_1_1, ..., p_m_1) => r_1
1158
+ // ...
1159
+ // (p_1_n, ..., p_m_n) => r_n
1160
+ val decomposedFormalsForArg : List [Option [(List [Type ], Type )]] =
1161
+ formalsForArg.map(defn.FunctionOf .unapply)
1162
+ if (decomposedFormalsForArg.forall(_.isDefined)) {
1163
+ val formalParamTypessForArg : List [List [Type ]] =
1164
+ decomposedFormalsForArg.map(_.get._1)
1165
+ if (isUniform(formalParamTypessForArg)((x, y) => x.length == y.length)) {
1166
+ val commonParamTypes = formalParamTypessForArg.transpose.map(ps =>
1167
+ // Given definitions above, for i = 1,...,m,
1168
+ // ps(i) = List(p_i_1, ..., p_i_n) -- i.e. a column
1169
+ // If all p_i_k's are the same, assume the type as formal parameter
1170
+ // type of the i'th parameter of the closure.
1171
+ if (isUniform(ps)(ctx.typeComparer.isSameTypeWhenFrozen(_, _))) ps.head
1172
+ else WildcardType )
1173
+ val commonFormal = defn.FunctionOf (commonParamTypes, WildcardType )
1174
+ overload.println(i " pretype arg $arg with expected type $commonFormal" )
1175
+ pt.typedArg(arg, commonFormal)
1176
+ }
1177
+ }
1178
+ case _ =>
1179
+ }
1180
+ recur(altFormals.map(_.tail), args1)
1181
+ case _ =>
1182
+ }
1183
+ def paramTypes (alt : Type ): List [Type ] = alt match {
1184
+ case mt : MethodType => mt.paramTypes
1185
+ case mt : PolyType => paramTypes(mt.resultType)
1186
+ case _ => Nil
1187
+ }
1188
+ recur(alts.map(alt => paramTypes(alt.widen)), pt.args)
1189
+ }
1190
+
1125
1191
private def harmonizeWith [T <: AnyRef ](ts : List [T ])(tpe : T => Type , adapt : (T , Type ) => T )(implicit ctx : Context ): List [T ] = {
1126
1192
def numericClasses (ts : List [T ], acc : Set [Symbol ]): Set [Symbol ] = ts match {
1127
1193
case t :: ts1 =>
0 commit comments