@@ -127,6 +127,9 @@ trait Applications extends Compatibility { self: Typer =>
127127 */
128128 protected def makeVarArg (n : Int , elemFormal : Type ): Unit
129129
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+
130133 /** Signal failure with given message at position of given argument */
131134 protected def fail (msg : => String , arg : Arg ): Unit
132135
@@ -334,7 +337,14 @@ trait Applications extends Compatibility { self: Typer =>
334337 addTyped(arg, formal)
335338 case _ =>
336339 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))
338348 makeVarArg(args.length, elemFormal)
339349 }
340350 else args match {
@@ -389,6 +399,7 @@ trait Applications extends Compatibility { self: Typer =>
389399 def argType (arg : Tree , formal : Type ): Type = normalize(arg.tpe, formal)
390400 def treeToArg (arg : Tree ): Tree = arg
391401 def isVarArg (arg : Tree ): Boolean = tpd.isWildcardStarArg(arg)
402+ def harmonizeArgs (args : List [Tree ]) = harmonize(args)
392403 }
393404
394405 /** Subclass of Application for applicability tests with type arguments and value
@@ -405,6 +416,7 @@ trait Applications extends Compatibility { self: Typer =>
405416 def argType (arg : Type , formal : Type ): Type = arg
406417 def treeToArg (arg : Tree ): Type = arg.tpe
407418 def isVarArg (arg : Type ): Boolean = arg.isRepeatedParam
419+ def harmonizeArgs (args : List [Type ]) = harmonizeTypes(args)
408420 }
409421
410422 /** Subclass of Application for type checking an Apply node, where
@@ -430,6 +442,8 @@ trait Applications extends Compatibility { self: Typer =>
430442 typedArgBuf += seqToRepeated(seqLit)
431443 }
432444
445+ def harmonizeArgs (args : List [TypedArg ]) = harmonize(args)
446+
433447 override def appPos = app.pos
434448
435449 def fail (msg : => String , arg : Trees .Tree [T ]) = {
@@ -1024,6 +1038,41 @@ trait Applications extends Compatibility { self: Typer =>
10241038 result
10251039 }
10261040 }
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)
10271076}
10281077
10291078/*
0 commit comments