Skip to content

Fix #5486: Constant-fold types in TypeAssigner #5506

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Decorators._, DenotTransformers._
import collection.mutable
import util.{Property, SourceFile, NoSource}
import NameKinds.{TempResultName, OuterSelectName}
import typer.ConstFold

import scala.annotation.tailrec
import scala.io.Codec
Expand Down Expand Up @@ -525,10 +526,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
tree match {
case tree: Select if qualifier.tpe eq tree.qualifier.tpe =>
tree1.withTypeUnchecked(tree.tpe)
case _ => tree.tpe match {
case tpe: NamedType => tree1.withType(tpe.derivedSelect(qualifier.tpe.widenIfUnstable))
case _ => tree1.withTypeUnchecked(tree.tpe)
}
case _ =>
val tree2 = tree.tpe match {
case tpe: NamedType => tree1.withType(tpe.derivedSelect(qualifier.tpe.widenIfUnstable))
case _ => tree1.withTypeUnchecked(tree.tpe)
}
ConstFold(tree2)
}
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Flags._
import Constants._
import Annotations._
import NameKinds._
import typer.ConstFold
import typer.Checking.checkNonCyclic
import util.Positions._
import ast.{TreeTypeMap, Trees, tpd, untpd}
Expand Down Expand Up @@ -996,7 +997,7 @@ class TreeUnpickler(reader: TastyReader,
val localCtx =
if (name == nme.CONSTRUCTOR) ctx.addMode(Mode.InSuperCall) else ctx
val qual = readTerm()(localCtx)
untpd.Select(qual, name).withType(tpf(qual.tpe.widenIfUnstable))
ConstFold(untpd.Select(qual, name).withType(tpf(qual.tpe.widenIfUnstable)))
}

def readQualId(): (untpd.Ident, TypeRef) = {
Expand Down
9 changes: 0 additions & 9 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -588,15 +588,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
// add type to term nodes; replace type nodes with their types unless -Yprint-pos is also set.
def tp = tree.typeOpt match {
case tp: TermRef if tree.isInstanceOf[RefTree] && !tp.denot.isOverloaded => tp.underlying
case tp: ConstantType if homogenizedView =>
// constant folded types are forgotten in Tasty, are reconstituted subsequently in FirstTransform.
// Therefore we have to gloss over this when comparing before/after pickling by widening to
// underlying type `T`, or, if expression is a unary primitive operation, to `=> T`.
tree match {
case Select(qual, _) if qual.typeOpt.widen.typeSymbol.isPrimitiveValueClass =>
ExprType(tp.widen)
case _ => tp.widen
}
case tp => tp
}
if (!suppressTypes)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt)
else
new ApplyToUntyped(tree, fun1, funRef, proto, pt)(argCtx(tree))
convertNewGenericArray(ConstFold(app.result))
convertNewGenericArray(app.result)
case _ =>
handleUnexpectedFunType(tree, fun1)
}
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/ConstFold.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ object ConstFold {
import tpd._

/** If tree is a constant operation, replace with result. */
def apply(tree: Tree)(implicit ctx: Context): Tree = finish(tree) {
def apply[T <: Tree](tree: T)(implicit ctx: Context): T = finish(tree) {
tree match {
case Apply(Select(xt, op), yt :: Nil) =>
xt.tpe.widenTermRefExpr match {
Expand All @@ -40,18 +40,18 @@ object ConstFold {
/** If tree is a constant value that can be converted to type `pt`, perform
* the conversion.
*/
def apply(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
def apply[T <: Tree](tree: T, pt: Type)(implicit ctx: Context): T =
finish(apply(tree)) {
tree.tpe.widenTermRefExpr match {
case ConstantType(x) => x convertTo pt
case _ => null
}
}

private def finish(tree: Tree)(compX: => Constant)(implicit ctx: Context): Tree =
private def finish[T <: Tree](tree: T)(compX: => Constant)(implicit ctx: Context): T =
try {
val x = compX
if (x ne null) tree withType ConstantType(x)
if (x ne null) tree.withType(ConstantType(x)).asInstanceOf[T]
else tree
} catch {
case _: ArithmeticException => tree // the code will crash at runtime,
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ trait TypeAssigner {

case _ => accessibleSelectionType(tree, qual)
}
tree.withType(tp)
ConstFold(tree.withType(tp))
}

def assignType(tree: untpd.New, tpt: Tree)(implicit ctx: Context): New =
Expand Down Expand Up @@ -372,7 +372,7 @@ trait TypeAssigner {
case t =>
errorType(err.takesNoParamsStr(fn, ""), tree.pos)
}
tree.withType(ownType)
ConstFold(tree.withType(ownType))
}

def assignType(tree: untpd.TypeApply, fn: Tree, args: List[Tree])(implicit ctx: Context): TypeApply = {
Expand Down
12 changes: 8 additions & 4 deletions tests/pos/constfold.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
object A {
val x = 2;
val y = x.asInstanceOf[Byte];
val z = 1.0 / 2;
val s = "z is " + z;
val x = 2
val y = x.asInstanceOf[Byte]
val z = 1.0 / 2
val s = "z is " + z

val a = 1 + 1
val b = -(1:1)
val c = -(1:1 & Any)
}

object Test extends App {
Expand Down
15 changes: 15 additions & 0 deletions tests/pos/inline-constfold.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
object Test {
inline def not(x: Boolean) <: Boolean = {
!x
}

final val a = not(true)
val b: false = a

inline def add(x: Int, y: Int) <: Int = {
x + y
}

final val c = add(3, 4)
val d: 7 = c
}