aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorGuillaume Martres <smarter@ubuntu.com>2015-04-04 01:15:16 +0200
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2015-05-01 13:27:42 +0200
commit411d5be477cc862b14d8938c591524d8bf37d4cd (patch)
tree3350ebafcea9888897c9eab47b82f748cbe9ed23 /src/dotty/tools/dotc
parent3fca64e2dfd53e376b3a45605100ef6f768b07a4 (diff)
downloaddotty-411d5be477cc862b14d8938c591524d8bf37d4cd.tar.gz
dotty-411d5be477cc862b14d8938c591524d8bf37d4cd.tar.bz2
dotty-411d5be477cc862b14d8938c591524d8bf37d4cd.zip
New phase: VCInline which inlines value classes calls
This corresponds roughly to step 2 of SIP-15 and to the peephole optimizations of step 3. The extractors in TreeExtractors are copied or inspired from src/compiler/scala/tools/nsc/ast/TreeInfo.scala in scalac.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/Compiler.scala1
-rw-r--r--src/dotty/tools/dotc/transform/InterceptedMethods.scala1
-rw-r--r--src/dotty/tools/dotc/transform/TreeExtractors.scala48
-rw-r--r--src/dotty/tools/dotc/transform/VCInline.scala59
4 files changed, 109 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index dc92187db..2b5748229 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -57,6 +57,7 @@ class Compiler {
new ResolveSuper),
List(new Erasure),
List(new ElimErasedValueType,
+ new VCInline,
new Mixin,
new LazyVals,
new Memoize,
diff --git a/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/src/dotty/tools/dotc/transform/InterceptedMethods.scala
index 725910949..ff354a54c 100644
--- a/src/dotty/tools/dotc/transform/InterceptedMethods.scala
+++ b/src/dotty/tools/dotc/transform/InterceptedMethods.scala
@@ -27,6 +27,7 @@ import scala.collection.mutable.ListBuffer
import dotty.tools.dotc.core.Denotations.SingleDenotation
import dotty.tools.dotc.core.SymDenotations.SymDenotation
import StdNames._
+import Phases.Phase
/** Replace member references as follows:
*
diff --git a/src/dotty/tools/dotc/transform/TreeExtractors.scala b/src/dotty/tools/dotc/transform/TreeExtractors.scala
new file mode 100644
index 000000000..7a5c5df9d
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/TreeExtractors.scala
@@ -0,0 +1,48 @@
+package dotty.tools.dotc
+package transform
+
+import ast.{Trees, tpd}
+import core._, core.Decorators._
+import Contexts._, Flags._, Trees._, Types._, StdNames._, Symbols._
+import ValueClasses._
+
+object TreeExtractors {
+ import tpd._
+
+ /** Match arg1.op(arg2) and extract (arg1, op.symbol, arg2) */
+ object BinaryOp {
+ def unapply(t: Tree)(implicit ctx: Context): Option[(Tree, Symbol, Tree)] = t match {
+ case Apply(sel @ Select(arg1, _), List(arg2)) =>
+ Some((arg1, sel.symbol, arg2))
+ case _ =>
+ None
+ }
+ }
+
+ /** Match new C(args) and extract (C, args) */
+ object NewWithArgs {
+ def unapply(t: Tree)(implicit ctx: Context): Option[(Type, List[Tree])] = t match {
+ case Apply(Select(New(_), nme.CONSTRUCTOR), args) =>
+ Some((t.tpe, args))
+ case _ =>
+ None
+ }
+ }
+
+ /** For an instance v of a value class like:
+ * class V(val underlying: X) extends AnyVal
+ * Match v.underlying() and extract v
+ */
+ object ValueClassUnbox {
+ def unapply(t: Tree)(implicit ctx: Context): Option[Tree] = t match {
+ case Apply(sel @ Select(ref, _), Nil) =>
+ val d = ref.tpe.widenDealias.typeSymbol.denot
+ if (isDerivedValueClass(d) && (sel.symbol eq valueClassUnbox(d.asClass))) {
+ Some(ref)
+ } else
+ None
+ case _ =>
+ None
+ }
+ }
+}
diff --git a/src/dotty/tools/dotc/transform/VCInline.scala b/src/dotty/tools/dotc/transform/VCInline.scala
new file mode 100644
index 000000000..e7b16f59e
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/VCInline.scala
@@ -0,0 +1,59 @@
+package dotty.tools.dotc
+package transform
+
+import ast.{Trees, tpd}
+import core._, core.Decorators._
+import Contexts._, Trees._, StdNames._, Symbols._
+import DenotTransformers._, TreeTransforms._, Phases.Phase
+import ExtensionMethods._, TreeExtractors._, ValueClasses._
+
+/** This phase inlines calls to methods and fields of value classes.
+ *
+ * For a value class V defined as:
+ * case class V(val underlying: U) extends AnyVal
+ * We replace method calls by calls to the corresponding extension method:
+ * v.foo(args) => V.foo$extension(v.underlying(), args)
+ * And we avoid unnecessary allocations:
+ * new V(u1) == new V(u2) => u1 == u2
+ * (new V(u)).underlying() => u
+ */
+class VCInline extends MiniPhaseTransform with IdentityDenotTransformer {
+ import tpd._
+
+ override def phaseName: String = "vcInline"
+
+ override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[ElimErasedValueType])
+
+ override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
+ tree match {
+ // new V(u1) == new V(u2) => u1 == u2
+ // (We don't handle != because it has been eliminated by InterceptedMethods)
+ case BinaryOp(NewWithArgs(tp1, List(u1)), op, NewWithArgs(tp2, List(u2)))
+ if (tp1 eq tp2) && (op eq defn.Any_==) && isDerivedValueClass(tp1.typeSymbol) =>
+ // == is overloaded in primitive classes
+ applyOverloaded(u1, nme.EQ, List(u2), Nil, defn.BooleanType)
+
+ // (new V(u)).underlying() => u
+ case ValueClassUnbox(NewWithArgs(_, List(u))) =>
+ u
+
+ // (new V(u)).foo(args) => V.foo$extension(u, args)
+ // v.foo(args) => V.foo$extension(v.underlying(), args)
+ case Apply(sel @ Select(receiver, _), args) =>
+ val classMeth = sel.symbol
+ if (isMethodWithExtension(classMeth)) {
+ val classSym = receiver.tpe.widenDealias.typeSymbol.asClass
+ val unboxedReceiver = receiver match {
+ case NewWithArgs(_, List(u)) =>
+ u
+ case _ =>
+ receiver.select(valueClassUnbox(classSym)).appliedToNone
+ }
+ val extensionMeth = extensionMethod(classMeth)
+ ref(extensionMeth).appliedToArgs(unboxedReceiver :: args)
+ } else tree
+
+ case _ =>
+ tree
+ }
+}