@@ -127,6 +127,9 @@ trait Applications extends Compatibility { self: Typer =>
127
127
*/
128
128
protected def makeVarArg (n : Int , elemFormal : Type ): Unit
129
129
130
+ /** If all `args` have primitive numeric types, make sure it's the same one */
131
+ protected def harmonizeArgs (args : List [TypedArg ]): List [TypedArg ]
132
+
130
133
/** Signal failure with given message at position of given argument */
131
134
protected def fail (msg : => String , arg : Arg ): Unit
132
135
@@ -334,7 +337,14 @@ trait Applications extends Compatibility { self: Typer =>
334
337
addTyped(arg, formal)
335
338
case _ =>
336
339
val elemFormal = formal.widenExpr.argTypesLo.head
337
- args foreach (addTyped(_, elemFormal))
340
+ val origConstraint = ctx.typerState.constraint
341
+ var typedArgs = args.map(typedArg(_, elemFormal))
342
+ val harmonizedArgs = harmonizeArgs(typedArgs)
343
+ if (harmonizedArgs ne typedArgs) {
344
+ ctx.typerState.constraint = origConstraint
345
+ typedArgs = harmonizedArgs
346
+ }
347
+ typedArgs.foreach(addArg(_, elemFormal))
338
348
makeVarArg(args.length, elemFormal)
339
349
}
340
350
else args match {
@@ -389,6 +399,7 @@ trait Applications extends Compatibility { self: Typer =>
389
399
def argType (arg : Tree , formal : Type ): Type = normalize(arg.tpe, formal)
390
400
def treeToArg (arg : Tree ): Tree = arg
391
401
def isVarArg (arg : Tree ): Boolean = tpd.isWildcardStarArg(arg)
402
+ def harmonizeArgs (args : List [Tree ]) = harmonize(args)
392
403
}
393
404
394
405
/** Subclass of Application for applicability tests with type arguments and value
@@ -405,6 +416,7 @@ trait Applications extends Compatibility { self: Typer =>
405
416
def argType (arg : Type , formal : Type ): Type = arg
406
417
def treeToArg (arg : Tree ): Type = arg.tpe
407
418
def isVarArg (arg : Type ): Boolean = arg.isRepeatedParam
419
+ def harmonizeArgs (args : List [Type ]) = harmonizeTypes(args)
408
420
}
409
421
410
422
/** Subclass of Application for type checking an Apply node, where
@@ -430,6 +442,8 @@ trait Applications extends Compatibility { self: Typer =>
430
442
typedArgBuf += seqToRepeated(seqLit)
431
443
}
432
444
445
+ def harmonizeArgs (args : List [TypedArg ]) = harmonize(args)
446
+
433
447
override def appPos = app.pos
434
448
435
449
def fail (msg : => String , arg : Trees .Tree [T ]) = {
@@ -1024,6 +1038,41 @@ trait Applications extends Compatibility { self: Typer =>
1024
1038
result
1025
1039
}
1026
1040
}
1041
+
1042
+ private def harmonizeWith [T <: AnyRef ](ts : List [T ])(tpe : T => Type , adapt : (T , Type ) => T )(implicit ctx : Context ): List [T ] = {
1043
+ def numericClasses (ts : List [T ], acc : Set [Symbol ]): Set [Symbol ] = ts match {
1044
+ case t :: ts1 =>
1045
+ val sym = tpe(t).widen.classSymbol
1046
+ if (sym.isNumericValueClass) numericClasses(ts1, acc + sym)
1047
+ else Set ()
1048
+ case Nil =>
1049
+ acc
1050
+ }
1051
+ val clss = numericClasses(ts, Set ())
1052
+ if (clss.size > 1 ) {
1053
+ val lub = defn.ScalaNumericValueClassList .find(lubCls =>
1054
+ clss.forall(defn.isValueSubClass(_, lubCls))).get.typeRef
1055
+ ts.mapConserve(adapt(_, lub))
1056
+ }
1057
+ else ts
1058
+ }
1059
+
1060
+ /** If `trees` all have numeric value types, and they do not have all the same type,
1061
+ * pick a common numeric supertype and convert all trees to this type.
1062
+ */
1063
+ def harmonize (trees : List [Tree ])(implicit ctx : Context ): List [Tree ] = {
1064
+ def adapt (tree : Tree , pt : Type ): Tree = tree match {
1065
+ case cdef : CaseDef => tpd.cpy.CaseDef (cdef)(body = adapt(cdef.body, pt))
1066
+ case _ => adaptInterpolated(tree, pt, tree)
1067
+ }
1068
+ harmonizeWith(trees)(_.tpe, adapt)
1069
+ }
1070
+
1071
+ /** If all `types` are numeric value types, and they are not all the same type,
1072
+ * pick a common numeric supertype and return it instead of every original type.
1073
+ */
1074
+ def harmonizeTypes (tpes : List [Type ])(implicit ctx : Context ): List [Type ] =
1075
+ harmonizeWith(tpes)(identity, (tp, pt) => pt)
1027
1076
}
1028
1077
1029
1078
/*
0 commit comments