aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/Compiler.scala3
-rw-r--r--src/dotty/tools/dotc/transform/Literalize.scala65
2 files changed, 67 insertions, 1 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index d202f3a52..b51f383f7 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -28,7 +28,8 @@ class Compiler {
new Splitter),
List(new Nullarify,
new TypeTestsCasts,
- new InterceptedMethods),
+ new InterceptedMethods,
+ new Literalize),
List(new Erasure),
List(new UncurryTreeTransform
/* , new Constructors */)
diff --git a/src/dotty/tools/dotc/transform/Literalize.scala b/src/dotty/tools/dotc/transform/Literalize.scala
new file mode 100644
index 000000000..14ce8fd05
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/Literalize.scala
@@ -0,0 +1,65 @@
+package dotty.tools.dotc
+package transform
+
+import TreeTransforms._
+import core.DenotTransformers._
+import core.Symbols._
+import core.Contexts._
+import core.Types._
+import core.Flags._
+import core.Decorators._
+import core.StdNames.nme
+import ast.Trees._
+
+/** This phase rewrites idempotent expressions with constant types to Literals.
+ * The constant types are eliminated by erasure, so we need to keep
+ * the info about constantness in the trees.
+ */
+class Literalize extends TreeTransform {
+ import ast.tpd._
+
+ override def name: String = "literalize"
+
+ /** Note: Demanding idempotency instead of purity is strictly speaking too loose.
+ * Example
+ *
+ * object O { final val x = 42; println("43") }
+ * O.x
+ *
+ * Strictly speaking we can't replace `O.x` with `42`. But this would make
+ * most expressions non-constant. Maybe we can change the spec to accept this
+ * kind of eliding behavior. Or else enforce true purity in the compiler.
+ * The choice will be affected by what we will do with `inline` and with
+ * Singleton type bounds (see SIP 23). Presumably
+ *
+ * object O1 { val x: Singleton = 42; println("43") }
+ * object O2 { inline val x = 42; println("43") }
+ *
+ * should behave differently.
+ *
+ * O1.x should have the same effect as { println("43"; 42 }
+ *
+ * whereas
+ *
+ * O2.x = 42
+ *
+ * Revisit this issue once we have implemented `inline`. Then we can demand
+ * purity of the prefix unless the selection goes to an inline val.
+ */
+ def literalize(tree: Tree)(implicit ctx: Context): Tree = tree.tpe match {
+ case ConstantType(value) if isIdempotentExpr(tree) => Literal(value)
+ case _ => tree
+ }
+
+ override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree =
+ literalize(tree)
+
+ override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree =
+ literalize(tree)
+
+ override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
+ literalize(tree)
+
+ override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree =
+ literalize(tree)
+} \ No newline at end of file