@@ -495,7 +495,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
495495 addTyped(arg, formal)
496496 case _ =>
497497 val elemFormal = formal.widenExpr.argTypesLo.head
498- val typedArgs = harmonic(harmonizeArgs)(args.map(typedArg(_, elemFormal)))
498+ val typedArgs =
499+ harmonic(harmonizeArgs, elemFormal)(args.map(typedArg(_, elemFormal)))
499500 typedArgs.foreach(addArg(_, elemFormal))
500501 makeVarArg(args.length, elemFormal)
501502 }
@@ -1541,38 +1542,33 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
15411542 }
15421543
15431544 private def harmonizeWith [T <: AnyRef ](ts : List [T ])(tpe : T => Type , adapt : (T , Type ) => T )(implicit ctx : Context ): List [T ] = {
1544- def numericClasses (ts : List [T ], acc : Set [ Symbol ] ): Set [ Symbol ] = ts match {
1545+ def targetClass (ts : List [T ], cls : Symbol , intLitSeen : Boolean ): Symbol = ts match {
15451546 case t :: ts1 =>
1546- val sym = tpe(t).widen.classSymbol
1547- if (sym.isNumericValueClass) numericClasses(ts1, acc + sym)
1548- else Set ()
1547+ tpe(t).widenTermRefExpr match {
1548+ case ConstantType (c : Constant ) if c.tag == IntTag =>
1549+ targetClass(ts1, cls, true )
1550+ case t =>
1551+ val sym = t.widen.classSymbol
1552+ if (! sym.isNumericValueClass || cls.exists && cls != sym) NoSymbol
1553+ else targetClass(ts1, sym, intLitSeen)
1554+ }
15491555 case Nil =>
1550- acc
1556+ if (cls != defn. IntClass && intLitSeen) cls else NoSymbol
15511557 }
1552- val clss = numericClasses(ts, Set ())
1553- if (clss.size > 1 ) {
1554- def isCompatible (cls : Symbol , sup : TypeRef ) =
1555- defn.isValueSubType(cls.typeRef, sup) &&
1556- ! (cls == defn.LongClass && sup.isRef(defn.FloatClass ))
1557- // exclude Long <: Float from list of allowable widenings
1558- // TODO: should we do this everywhere we ask for isValueSubType?
1559-
1560- val lub = defn.ScalaNumericValueTypeList .find(lubTpe =>
1561- clss.forall(cls => isCompatible(cls, lubTpe))).get
1562-
1563- def lossOfPrecision (ct : Constant ): Boolean =
1564- ct.tag == IntTag && lub.isRef(defn.FloatClass ) &&
1565- ct.intValue.toFloat.toInt != ct.intValue ||
1566- ct.tag == LongTag && lub.isRef(defn.DoubleClass ) &&
1567- ct.longValue.toDouble.toLong != ct.longValue
1568-
1558+ val cls = targetClass(ts, NoSymbol , false )
1559+ if (cls.exists) {
1560+ def lossOfPrecision (n : Int ): Boolean =
1561+ cls == defn.FloatClass && n.toFloat.toInt != n
1562+ var canAdapt = true
15691563 val ts1 = ts.mapConserve { t =>
15701564 tpe(t).widenTermRefExpr match {
1571- case ct : ConstantType if ! lossOfPrecision(ct.value) => adapt(t, lub)
1565+ case ConstantType (c : Constant ) if c.tag == IntTag =>
1566+ canAdapt &= c.convertTo(cls.typeRef) != null && ! lossOfPrecision(c.intValue)
1567+ if (canAdapt) adapt(t, cls.typeRef) else t
15721568 case _ => t
15731569 }
15741570 }
1575- if (numericClasses(ts1, Set ()).size == 1 ) ts1 else ts
1571+ if (canAdapt ) ts1 else ts
15761572 }
15771573 else ts
15781574 }
@@ -1589,7 +1585,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
15891585 if (ctx.isAfterTyper) trees else harmonizeWith(trees)(_.tpe, adaptDeep)
15901586 }
15911587
1592- /** Apply a transformation `harmonize` on the results of operation `op`.
1588+ /** Apply a transformation `harmonize` on the results of operation `op`,
1589+ * unless the expected type `pt` is fully defined.
15931590 * If the result is different (wrt eq) from the original results of `op`,
15941591 * revert back to the constraint in force before computing `op`.
15951592 * This reset is needed because otherwise the original results might
@@ -1598,13 +1595,15 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
15981595 * the result of harmomization will be compared again with the expected type.
15991596 * Test cases where this matters are in pos/harmomize.scala.
16001597 */
1601- def harmonic [T ](harmonize : List [T ] => List [T ])(op : => List [T ])(implicit ctx : Context ): List [T ] = {
1602- val origConstraint = ctx.typerState.constraint
1603- val origElems = op
1604- val harmonizedElems = harmonize(origElems)
1605- if (harmonizedElems ne origElems) ctx.typerState.constraint = origConstraint
1606- harmonizedElems
1607- }
1598+ def harmonic [T ](harmonize : List [T ] => List [T ], pt : Type )(op : => List [T ])(implicit ctx : Context ): List [T ] =
1599+ if (! isFullyDefined(pt, ForceDegree .none)) {
1600+ val origConstraint = ctx.typerState.constraint
1601+ val origElems = op
1602+ val harmonizedElems = harmonize(origElems)
1603+ if (harmonizedElems ne origElems) ctx.typerState.constraint = origConstraint
1604+ harmonizedElems
1605+ }
1606+ else op
16081607
16091608 /** If all `types` are numeric value types, and they are not all the same type,
16101609 * pick a common numeric supertype and widen any constant types in `tpes` to it.
0 commit comments