@@ -509,7 +509,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
509509 addTyped(arg, formal)
510510 case _ =>
511511 val elemFormal = formal.widenExpr.argTypesLo.head
512- val typedArgs = harmonic(harmonizeArgs)(args.map(typedArg(_, elemFormal)))
512+ val typedArgs =
513+ harmonic(harmonizeArgs, elemFormal)(args.map(typedArg(_, elemFormal)))
513514 typedArgs.foreach(addArg(_, elemFormal))
514515 makeVarArg(args.length, elemFormal)
515516 }
@@ -1555,38 +1556,33 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
15551556 }
15561557
15571558 private def harmonizeWith [T <: AnyRef ](ts : List [T ])(tpe : T => Type , adapt : (T , Type ) => T )(implicit ctx : Context ): List [T ] = {
1558- def numericClasses (ts : List [T ], acc : Set [ Symbol ] ): Set [ Symbol ] = ts match {
1559+ def targetClass (ts : List [T ], cls : Symbol , intLitSeen : Boolean ): Symbol = ts match {
15591560 case t :: ts1 =>
1560- val sym = tpe(t).widen.classSymbol
1561- if (sym.isNumericValueClass) numericClasses(ts1, acc + sym)
1562- else Set ()
1561+ tpe(t).widenTermRefExpr match {
1562+ case ConstantType (c : Constant ) if c.tag == IntTag =>
1563+ targetClass(ts1, cls, true )
1564+ case t =>
1565+ val sym = t.widen.classSymbol
1566+ if (! sym.isNumericValueClass || cls.exists && cls != sym) NoSymbol
1567+ else targetClass(ts1, sym, intLitSeen)
1568+ }
15631569 case Nil =>
1564- acc
1570+ if (cls != defn. IntClass && intLitSeen) cls else NoSymbol
15651571 }
1566- val clss = numericClasses(ts, Set ())
1567- if (clss.size > 1 ) {
1568- def isCompatible (cls : Symbol , sup : TypeRef ) =
1569- defn.isValueSubType(cls.typeRef, sup) &&
1570- ! (cls == defn.LongClass && sup.isRef(defn.FloatClass ))
1571- // exclude Long <: Float from list of allowable widenings
1572- // TODO: should we do this everywhere we ask for isValueSubType?
1573-
1574- val lub = defn.ScalaNumericValueTypeList .find(lubTpe =>
1575- clss.forall(cls => isCompatible(cls, lubTpe))).get
1576-
1577- def lossOfPrecision (ct : Constant ): Boolean =
1578- ct.tag == IntTag && lub.isRef(defn.FloatClass ) &&
1579- ct.intValue.toFloat.toInt != ct.intValue ||
1580- ct.tag == LongTag && lub.isRef(defn.DoubleClass ) &&
1581- ct.longValue.toDouble.toLong != ct.longValue
1582-
1572+ val cls = targetClass(ts, NoSymbol , false )
1573+ if (cls.exists) {
1574+ def lossOfPrecision (n : Int ): Boolean =
1575+ cls == defn.FloatClass && n.toFloat.toInt != n
1576+ var canAdapt = true
15831577 val ts1 = ts.mapConserve { t =>
15841578 tpe(t).widenTermRefExpr match {
1585- case ct : ConstantType if ! lossOfPrecision(ct.value) => adapt(t, lub)
1579+ case ConstantType (c : Constant ) if c.tag == IntTag =>
1580+ canAdapt &= c.convertTo(cls.typeRef) != null && ! lossOfPrecision(c.intValue)
1581+ if (canAdapt) adapt(t, cls.typeRef) else t
15861582 case _ => t
15871583 }
15881584 }
1589- if (numericClasses(ts1, Set ()).size == 1 ) ts1 else ts
1585+ if (canAdapt ) ts1 else ts
15901586 }
15911587 else ts
15921588 }
@@ -1603,7 +1599,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
16031599 if (ctx.isAfterTyper) trees else harmonizeWith(trees)(_.tpe, adaptDeep)
16041600 }
16051601
1606- /** Apply a transformation `harmonize` on the results of operation `op`.
1602+ /** Apply a transformation `harmonize` on the results of operation `op`,
1603+ * unless the expected type `pt` is fully defined.
16071604 * If the result is different (wrt eq) from the original results of `op`,
16081605 * revert back to the constraint in force before computing `op`.
16091606 * This reset is needed because otherwise the original results might
@@ -1612,13 +1609,15 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
16121609 * the result of harmomization will be compared again with the expected type.
16131610 * Test cases where this matters are in pos/harmomize.scala.
16141611 */
1615- def harmonic [T ](harmonize : List [T ] => List [T ])(op : => List [T ])(implicit ctx : Context ): List [T ] = {
1616- val origConstraint = ctx.typerState.constraint
1617- val origElems = op
1618- val harmonizedElems = harmonize(origElems)
1619- if (harmonizedElems ne origElems) ctx.typerState.constraint = origConstraint
1620- harmonizedElems
1621- }
1612+ def harmonic [T ](harmonize : List [T ] => List [T ], pt : Type )(op : => List [T ])(implicit ctx : Context ): List [T ] =
1613+ if (! isFullyDefined(pt, ForceDegree .none)) {
1614+ val origConstraint = ctx.typerState.constraint
1615+ val origElems = op
1616+ val harmonizedElems = harmonize(origElems)
1617+ if (harmonizedElems ne origElems) ctx.typerState.constraint = origConstraint
1618+ harmonizedElems
1619+ }
1620+ else op
16221621
16231622 /** If all `types` are numeric value types, and they are not all the same type,
16241623 * pick a common numeric supertype and widen any constant types in `tpes` to it.
0 commit comments