@@ -509,7 +509,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
509
509
addTyped(arg, formal)
510
510
case _ =>
511
511
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)))
513
514
typedArgs.foreach(addArg(_, elemFormal))
514
515
makeVarArg(args.length, elemFormal)
515
516
}
@@ -1555,38 +1556,33 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
1555
1556
}
1556
1557
1557
1558
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 {
1559
1560
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
+ }
1563
1569
case Nil =>
1564
- acc
1570
+ if (cls != defn. IntClass && intLitSeen) cls else NoSymbol
1565
1571
}
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
1583
1577
val ts1 = ts.mapConserve { t =>
1584
1578
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
1586
1582
case _ => t
1587
1583
}
1588
1584
}
1589
- if (numericClasses(ts1, Set ()).size == 1 ) ts1 else ts
1585
+ if (canAdapt ) ts1 else ts
1590
1586
}
1591
1587
else ts
1592
1588
}
@@ -1603,7 +1599,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
1603
1599
if (ctx.isAfterTyper) trees else harmonizeWith(trees)(_.tpe, adaptDeep)
1604
1600
}
1605
1601
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.
1607
1604
* If the result is different (wrt eq) from the original results of `op`,
1608
1605
* revert back to the constraint in force before computing `op`.
1609
1606
* This reset is needed because otherwise the original results might
@@ -1612,13 +1609,15 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
1612
1609
* the result of harmomization will be compared again with the expected type.
1613
1610
* Test cases where this matters are in pos/harmomize.scala.
1614
1611
*/
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
1622
1621
1623
1622
/** If all `types` are numeric value types, and they are not all the same type,
1624
1623
* pick a common numeric supertype and widen any constant types in `tpes` to it.
0 commit comments