Skip to content

Commit 47ebafe

Browse files
committed
Fix #5486: Constant-fold types in TypeAssigner
To be consistent we also need to do it in TreeUnpickler and TypedTreeCopier because they don't use TypeAssigner for Select nodes. The main reason for this change is that it ensures that the pickled and unpickled trees have the same constant types, but it also means that inlined trees can get more precise types as witnessed by the added inline-constfold.scala test
1 parent 052c3b1 commit 47ebafe

File tree

8 files changed

+39
-25
lines changed

8 files changed

+39
-25
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Decorators._, DenotTransformers._
1313
import collection.mutable
1414
import util.{Property, SourceFile, NoSource}
1515
import NameKinds.{TempResultName, OuterSelectName}
16+
import typer.ConstFold
1617

1718
import scala.annotation.tailrec
1819
import scala.io.Codec
@@ -525,10 +526,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
525526
tree match {
526527
case tree: Select if qualifier.tpe eq tree.qualifier.tpe =>
527528
tree1.withTypeUnchecked(tree.tpe)
528-
case _ => tree.tpe match {
529-
case tpe: NamedType => tree1.withType(tpe.derivedSelect(qualifier.tpe.widenIfUnstable))
530-
case _ => tree1.withTypeUnchecked(tree.tpe)
531-
}
529+
case _ =>
530+
val tree2 = tree.tpe match {
531+
case tpe: NamedType => tree1.withType(tpe.derivedSelect(qualifier.tpe.widenIfUnstable))
532+
case _ => tree1.withTypeUnchecked(tree.tpe)
533+
}
534+
ConstFold(tree2)
532535
}
533536
}
534537

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Flags._
1616
import Constants._
1717
import Annotations._
1818
import NameKinds._
19+
import typer.ConstFold
1920
import typer.Checking.checkNonCyclic
2021
import util.Positions._
2122
import ast.{TreeTypeMap, Trees, tpd, untpd}
@@ -996,7 +997,7 @@ class TreeUnpickler(reader: TastyReader,
996997
val localCtx =
997998
if (name == nme.CONSTRUCTOR) ctx.addMode(Mode.InSuperCall) else ctx
998999
val qual = readTerm()(localCtx)
999-
untpd.Select(qual, name).withType(tpf(qual.tpe.widenIfUnstable))
1000+
ConstFold(untpd.Select(qual, name).withType(tpf(qual.tpe.widenIfUnstable)))
10001001
}
10011002

10021003
def readQualId(): (untpd.Ident, TypeRef) = {

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -588,15 +588,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
588588
// add type to term nodes; replace type nodes with their types unless -Yprint-pos is also set.
589589
def tp = tree.typeOpt match {
590590
case tp: TermRef if tree.isInstanceOf[RefTree] && !tp.denot.isOverloaded => tp.underlying
591-
case tp: ConstantType if homogenizedView =>
592-
// constant folded types are forgotten in Tasty, are reconstituted subsequently in FirstTransform.
593-
// Therefore we have to gloss over this when comparing before/after pickling by widening to
594-
// underlying type `T`, or, if expression is a unary primitive operation, to `=> T`.
595-
tree match {
596-
case Select(qual, _) if qual.typeOpt.widen.typeSymbol.isPrimitiveValueClass =>
597-
ExprType(tp.widen)
598-
case _ => tp.widen
599-
}
600591
case tp => tp
601592
}
602593
if (!suppressTypes)

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
769769
new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt)
770770
else
771771
new ApplyToUntyped(tree, fun1, funRef, proto, pt)(argCtx(tree))
772-
convertNewGenericArray(ConstFold(app.result))
772+
convertNewGenericArray(app.result)
773773
case _ =>
774774
handleUnexpectedFunType(tree, fun1)
775775
}

compiler/src/dotty/tools/dotc/typer/ConstFold.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object ConstFold {
1717
import tpd._
1818

1919
/** If tree is a constant operation, replace with result. */
20-
def apply(tree: Tree)(implicit ctx: Context): Tree = finish(tree) {
20+
def apply[T <: Tree](tree: T)(implicit ctx: Context): T = finish(tree) {
2121
tree match {
2222
case Apply(Select(xt, op), yt :: Nil) =>
2323
xt.tpe.widenTermRefExpr match {
@@ -40,18 +40,18 @@ object ConstFold {
4040
/** If tree is a constant value that can be converted to type `pt`, perform
4141
* the conversion.
4242
*/
43-
def apply(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
43+
def apply[T <: Tree](tree: T, pt: Type)(implicit ctx: Context): T =
4444
finish(apply(tree)) {
4545
tree.tpe.widenTermRefExpr match {
4646
case ConstantType(x) => x convertTo pt
4747
case _ => null
4848
}
4949
}
5050

51-
private def finish(tree: Tree)(compX: => Constant)(implicit ctx: Context): Tree =
51+
private def finish[T <: Tree](tree: T)(compX: => Constant)(implicit ctx: Context): T =
5252
try {
5353
val x = compX
54-
if (x ne null) tree withType ConstantType(x)
54+
if (x ne null) tree.withType(ConstantType(x)).asInstanceOf[T]
5555
else tree
5656
} catch {
5757
case _: ArithmeticException => tree // the code will crash at runtime,

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ trait TypeAssigner {
291291

292292
case _ => accessibleSelectionType(tree, qual)
293293
}
294-
tree.withType(tp)
294+
ConstFold(tree.withType(tp))
295295
}
296296

297297
def assignType(tree: untpd.New, tpt: Tree)(implicit ctx: Context): New =
@@ -372,7 +372,7 @@ trait TypeAssigner {
372372
case t =>
373373
errorType(err.takesNoParamsStr(fn, ""), tree.pos)
374374
}
375-
tree.withType(ownType)
375+
ConstFold(tree.withType(ownType))
376376
}
377377

378378
def assignType(tree: untpd.TypeApply, fn: Tree, args: List[Tree])(implicit ctx: Context): TypeApply = {

tests/pos/constfold.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
object A {
2-
val x = 2;
3-
val y = x.asInstanceOf[Byte];
4-
val z = 1.0 / 2;
5-
val s = "z is " + z;
2+
val x = 2
3+
val y = x.asInstanceOf[Byte]
4+
val z = 1.0 / 2
5+
val s = "z is " + z
6+
7+
val a = 1 + 1
8+
val b = -(1:1)
9+
val c = -(1:1 & Any)
610
}
711

812
object Test extends App {

tests/pos/inline-constfold.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
object Test {
2+
inline def not(x: Boolean) <: Boolean = {
3+
!x
4+
}
5+
6+
final val a = not(true)
7+
val b: false = a
8+
9+
inline def add(x: Int, y: Int) <: Int = {
10+
x + y
11+
}
12+
13+
final val c = add(3, 4)
14+
val d: 7 = c
15+
}

0 commit comments

Comments
 (0)