Skip to content

Commit 9e1759f

Browse files
committed
Merge pull request #140 from dotty-staging/transform/extensionMethods
Transform/extension methods
2 parents bdbed39 + 736dceb commit 9e1759f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+2095
-422
lines changed

src/dotty/tools/dotc/Compiler.scala

+6-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import reporting.ConsoleReporter
1111
import dotty.tools.dotc.core.Phases.Phase
1212
import dotty.tools.dotc.transform._
1313
import dotty.tools.dotc.transform.TreeTransforms.{TreeTransform, TreeTransformer}
14-
import dotty.tools.dotc.transform.PostTyperTransformers.PostTyperTransformer
1514
import dotty.tools.dotc.core.DenotTransformers.DenotTransformer
1615
import dotty.tools.dotc.core.Denotations.SingleDenotation
1716

@@ -20,14 +19,17 @@ class Compiler {
2019
def phases: List[List[Phase]] =
2120
List(
2221
List(new FrontEnd),
23-
List(new LazyValsCreateCompanionObjects,
24-
new TailRec), //force separataion between lazyVals and LVCreateCO
22+
List(new Companions, new ElimRepeated /*, new ElimLocals*/),
23+
List(new SuperAccessors),
24+
List(new ExtensionMethods),
25+
List(new TailRec),
2526
List(new PatternMatcher,
2627
new LazyValTranformContext().transformer,
2728
new Splitter),
2829
List(new Nullarify,
2930
new TypeTestsCasts,
30-
new InterceptedMethods),
31+
new InterceptedMethods,
32+
new Literalize),
3133
List(new Erasure),
3234
List(new UncurryTreeTransform
3335
/* , new Constructors */)

src/dotty/tools/dotc/ElimLocals.scala

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer}
6+
import DenotTransformers._
7+
8+
/** Widens all private[this] and protected[this] qualifiers to just private/protected */
9+
abstract class ElimLocals extends TreeTransform with InfoTransformer { thisTransformer =>
10+
11+
// TODO complete
12+
13+
}

src/dotty/tools/dotc/ast/TreeInfo.scala

+55-26
Original file line numberDiff line numberDiff line change
@@ -282,41 +282,46 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
282282

283283
trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
284284

285-
/** Is tree a definition that has no side effects when
286-
* evaluated as part of a block after the first time?
285+
/** The purity level of this statement.
286+
* @return pure if statement has no side effects
287+
* idempotent if running the statement a second time has no side effects
288+
* impure otherwise
287289
*/
288-
def isIdempotentDef(tree: tpd.Tree)(implicit ctx: Context): Boolean = unsplice(tree) match {
290+
private def statPurity(tree: tpd.Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
289291
case EmptyTree
290292
| TypeDef(_, _, _)
291293
| Import(_, _)
292294
| DefDef(_, _, _, _, _, _) =>
293-
true
295+
Pure
294296
case ValDef(mods, _, _, rhs) =>
295-
!(mods is Mutable) && isIdempotentExpr(rhs)
297+
if (mods is Mutable) Impure else exprPurity(rhs)
296298
case _ =>
297-
false
299+
Impure
298300
}
299301

300-
/** Is tree an expression which can be inlined without affecting program semantics?
302+
/** The purity level of this expression.
303+
* @return pure if expression has no side effects
304+
* idempotent if running the expression a second time has no side effects
305+
* impure otherwise
301306
*
302-
* Note that this is not called "isExprPure" since purity (lack of side-effects)
303-
* is not the litmus test. References to modules and lazy vals are side-effecting,
304-
* both because side-effecting code may be executed and because the first reference
305-
* takes a different code path than all to follow; but they are safe to inline
306-
* because the expression result from evaluating them is always the same.
307+
* Note that purity and idempotency are different. References to modules and lazy
308+
* vals are impure (side-effecting) both because side-effecting code may be executed and because the first reference
309+
* takes a different code path than all to follow; but they are idempotent
310+
* because running the expression a second time gives the cached result.
307311
*/
308-
def isIdempotentExpr(tree: tpd.Tree)(implicit ctx: Context): Boolean = unsplice(tree) match {
312+
private def exprPurity(tree: tpd.Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
309313
case EmptyTree
310314
| This(_)
311315
| Super(_, _)
312316
| Literal(_) =>
313-
true
317+
Pure
314318
case Ident(_) =>
315-
isIdempotentRef(tree)
319+
refPurity(tree)
316320
case Select(qual, _) =>
317-
isIdempotentRef(tree) && isIdempotentExpr(qual)
321+
refPurity(tree).min(
322+
if (tree.symbol.is(Inline)) Pure else exprPurity(qual))
318323
case TypeApply(fn, _) =>
319-
isIdempotentExpr(fn)
324+
exprPurity(fn)
320325
/*
321326
* Not sure we'll need that. Comment out until we find out
322327
case Apply(Select(free @ Ident(_), nme.apply), _) if free.symbol.name endsWith nme.REIFY_FREE_VALUE_SUFFIX =>
@@ -326,21 +331,36 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
326331
case Apply(fn, Nil) =>
327332
// Note: After uncurry, field accesses are represented as Apply(getter, Nil),
328333
// so an Apply can also be pure.
329-
// However, before typing, applications of nullary functional values are also
330-
// Apply(function, Nil) trees. To prevent them from being treated as pure,
331-
// we check that the callee is a method.
332-
// The callee might also be a Block, which has a null symbol, so we guard against that (SI-7185)
333-
fn.symbol != null && (fn.symbol is (Method, butNot = Lazy)) && isIdempotentExpr(fn)
334+
if (fn.symbol is Stable) exprPurity(fn) else Impure
334335
case Typed(expr, _) =>
335-
isIdempotentExpr(expr)
336+
exprPurity(expr)
336337
case Block(stats, expr) =>
337-
(stats forall isIdempotentDef) && isIdempotentExpr(expr)
338+
(exprPurity(expr) /: stats.map(statPurity))(_ min _)
338339
case _ =>
339-
false
340+
Impure
340341
}
341342

343+
def isPureExpr(tree: tpd.Tree)(implicit ctx: Context) = exprPurity(tree) == Pure
344+
def isIdempotentExpr(tree: tpd.Tree)(implicit ctx: Context) = exprPurity(tree) >= Idempotent
345+
346+
/** The purity level of this reference.
347+
* @return
348+
* pure if reference is (nonlazy and stable) or to a parameterized function
349+
* idempotent if reference is lazy and stable
350+
* impure otherwise
351+
* @DarkDimius: need to make sure that lazy accessor methods have Lazy and Stable
352+
* flags set.
353+
*/
354+
private def refPurity(tree: tpd.Tree)(implicit ctx: Context): PurityLevel =
355+
if (!tree.tpe.widen.isParameterless) Pure
356+
else if (!tree.symbol.is(Stable)) Impure
357+
else if (tree.symbol.is(Lazy)) Idempotent // TODO add Module flag, sinxce Module vals or not Lazy from the start.
358+
else Pure
359+
360+
def isPureRef(tree: tpd.Tree)(implicit ctx: Context) =
361+
refPurity(tree) == Pure
342362
def isIdempotentRef(tree: tpd.Tree)(implicit ctx: Context) =
343-
tree.symbol.isStable || !tree.tpe.widen.isParameterless
363+
refPurity(tree) >= Idempotent
344364

345365
/** Is symbol potentially a getter of a mutable variable?
346366
*/
@@ -456,6 +476,15 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
456476
case nil =>
457477
Nil
458478
}
479+
480+
private class PurityLevel(val x: Int) {
481+
def >= (that: PurityLevel) = x >= that.x
482+
def min(that: PurityLevel) = new PurityLevel(x min that.x)
483+
}
484+
485+
private val Pure = new PurityLevel(2)
486+
private val Idempotent = new PurityLevel(1)
487+
private val Impure = new PurityLevel(0)
459488
}
460489

461490
/** a Match(Typed(_, tpt), _) must be translated into a switch if isSwitchAnnotation(tpt.tpe)

src/dotty/tools/dotc/ast/Trees.scala

+3
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ object Trees {
361361
type ThisTree[-T >: Untyped] <: DenotingTree[T]
362362
override def denot(implicit ctx: Context) = tpe match {
363363
case tpe: NamedType => tpe.denot
364+
case ThisType(cls) => cls.denot
364365
case _ => NoDenotation
365366
}
366367
}
@@ -1162,6 +1163,8 @@ object Trees {
11621163
cpy.Alternative(tree, transform(trees))
11631164
case UnApply(fun, implicits, patterns) =>
11641165
cpy.UnApply(tree, transform(fun), transform(implicits), transform(patterns))
1166+
case EmptyValDef =>
1167+
tree
11651168
case ValDef(mods, name, tpt, rhs) =>
11661169
cpy.ValDef(tree, mods, name, transform(tpt), transform(rhs))
11671170
case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>

0 commit comments

Comments
 (0)