Skip to content

Transform/extension methods #140

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 47 commits into from
Jul 17, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
d8864d3
Add cloneScope method and handle versioning of ClassInfo#decls
odersky Jun 18, 2014
65eb50f
Make SuperAccessorName and extractor.
odersky Jun 18, 2014
8b93f7b
Added MacroTransform as a transformer template for macro phases.
odersky Jun 27, 2014
2e15951
New utitility methods in tpd.
odersky Jul 1, 2014
a2a5a57
ThisType trees have their class as a denotation
odersky Jul 1, 2014
0cf64e8
Error method for implementation restrictions
odersky Jul 1, 2014
8112a39
Improved printing of flags
odersky Jul 1, 2014
3ab2784
Added phase: SuperAccessors
odersky Jul 1, 2014
f0249f2
Rename SignedType -> MethodicType
odersky Jul 1, 2014
968d16c
Fixed problem with installAfter
odersky Jul 3, 2014
a47b8b4
Removed test case
odersky Jul 3, 2014
efe4f7e
Changed PostTyperTransformer scheme
odersky Jul 3, 2014
db88bf0
Various cleanups and utility additions
odersky Jul 3, 2014
3570030
ExtensionMethods phase and TypeUtils
odersky Jul 3, 2014
3001346
Added infix methods for some tree constructions
odersky Jul 5, 2014
1fdc188
New micro phase: Literalize
odersky Jul 5, 2014
5428549
New Flag: Inline
odersky Jul 6, 2014
4aa934b
Revised purity tests in TreeInfo
odersky Jul 6, 2014
ab8d873
Fix bad type passed to indexOf.
odersky Jul 6, 2014
3eabbb7
Move valueclass functionality into its own ValueClass module.
odersky Jul 7, 2014
8b1e58f
Add definedPeriodsString method for disgnostics.
odersky Jul 8, 2014
8d41e9d
Make TypeParamCreation flags depend on owner
odersky Jul 10, 2014
7b13a86
Invalidate member caches in different periods
odersky Jul 10, 2014
05120fc
Fixes to MacroTransform and TreeTransformer
odersky Jul 10, 2014
cd82c85
Make more Definition methods depend on implicit context argument
odersky Jul 10, 2014
34202eb
Avoid some classes of StaleSymbol errors
odersky Jul 10, 2014
1ac95a7
Add unique ids for definitions
odersky Jul 10, 2014
1bb16c4
Small cleanups and additions.
odersky Jul 10, 2014
290343c
Fixes to TypeUtils
odersky Jul 10, 2014
dce9d6d
New phase: ElimRepeated
odersky Jul 10, 2014
1d4c5f6
Revamped TreeTypeMap
odersky Jul 10, 2014
fc784b8
Enabled ExtensionMethods
odersky Jul 10, 2014
4a08703
Silenced ElimRepeated.
odersky Jul 10, 2014
58f249d
Simplification: dynamicSignature instead of toDynamic
odersky Jul 11, 2014
ec972b7
Fix problem with dynamicSignature.
odersky Jul 11, 2014
47bf266
Made ExtensionMethods work as an InfoTransformer
odersky Jul 11, 2014
90965ab
Semantic printing
odersky Jul 13, 2014
dee5f09
Avoid forming SeqLiterals with singleton type element.
odersky Jul 13, 2014
8a0ce6d
Fixes to TreeTypeMap
odersky Jul 13, 2014
65a8570
Fixes to ReTyper
odersky Jul 13, 2014
3f3581c
Make ExtensionMethods not rely on TailRec
odersky Jul 13, 2014
57d69f8
Refactored reusable full parameterization code into base trait.
odersky Jul 13, 2014
ace968d
Fix to rewire types
odersky Jul 14, 2014
37c6e42
Fixed problem with missing denotations in polyDefDef
odersky Jul 16, 2014
7c56a5b
Make self types always include a reference to the class
odersky Jul 16, 2014
491e076
Handle selftypes in FullParameterization
odersky Jul 16, 2014
736dceb
Made FullParameterization more customizable
odersky Jul 17, 2014
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
10 changes: 6 additions & 4 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import reporting.ConsoleReporter
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.transform._
import dotty.tools.dotc.transform.TreeTransforms.{TreeTransform, TreeTransformer}
import dotty.tools.dotc.transform.PostTyperTransformers.PostTyperTransformer
import dotty.tools.dotc.core.DenotTransformers.DenotTransformer
import dotty.tools.dotc.core.Denotations.SingleDenotation

Expand All @@ -20,14 +19,17 @@ class Compiler {
def phases: List[List[Phase]] =
List(
List(new FrontEnd),
List(new LazyValsCreateCompanionObjects,
new TailRec), //force separataion between lazyVals and LVCreateCO
List(new Companions, new ElimRepeated /*, new ElimLocals*/),
List(new SuperAccessors),
List(new ExtensionMethods),
List(new TailRec),
List(new PatternMatcher,
new LazyValTranformContext().transformer,
new Splitter),
List(new Nullarify,
new TypeTestsCasts,
new InterceptedMethods),
new InterceptedMethods,
new Literalize),
List(new Erasure),
List(new UncurryTreeTransform
/* , new Constructors */)
Expand Down
13 changes: 13 additions & 0 deletions src/dotty/tools/dotc/ElimLocals.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dotty.tools.dotc
package transform

import core._
import TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer}
import DenotTransformers._

/** Widens all private[this] and protected[this] qualifiers to just private/protected */
abstract class ElimLocals extends TreeTransform with InfoTransformer { thisTransformer =>

// TODO complete

}
81 changes: 55 additions & 26 deletions src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -282,41 +282,46 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]

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

/** Is tree a definition that has no side effects when
* evaluated as part of a block after the first time?
/** The purity level of this statement.
* @return pure if statement has no side effects
* idempotent if running the statement a second time has no side effects
* impure otherwise
*/
def isIdempotentDef(tree: tpd.Tree)(implicit ctx: Context): Boolean = unsplice(tree) match {
private def statPurity(tree: tpd.Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
case EmptyTree
| TypeDef(_, _, _)
| Import(_, _)
| DefDef(_, _, _, _, _, _) =>
true
Pure
case ValDef(mods, _, _, rhs) =>
!(mods is Mutable) && isIdempotentExpr(rhs)
if (mods is Mutable) Impure else exprPurity(rhs)
case _ =>
false
Impure
}

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

def isPureExpr(tree: tpd.Tree)(implicit ctx: Context) = exprPurity(tree) == Pure
def isIdempotentExpr(tree: tpd.Tree)(implicit ctx: Context) = exprPurity(tree) >= Idempotent

/** The purity level of this reference.
* @return
* pure if reference is (nonlazy and stable) or to a parameterized function
* idempotent if reference is lazy and stable
* impure otherwise
* @DarkDimius: need to make sure that lazy accessor methods have Lazy and Stable
* flags set.
*/
private def refPurity(tree: tpd.Tree)(implicit ctx: Context): PurityLevel =
if (!tree.tpe.widen.isParameterless) Pure
else if (!tree.symbol.is(Stable)) Impure
else if (tree.symbol.is(Lazy)) Idempotent // TODO add Module flag, sinxce Module vals or not Lazy from the start.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lazy vals aren't actually idempotent.

scala> import util._; object O { lazy val foo = { println("!!"); ??? } }; Try(O.foo); Try(O.foo); ""
!!
!!
import util._
defined object O
res0: String = ""

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but we'd like to treat them as such for evalOnce, right? Looks like we need a better effect analysis to make any progress here.

else Pure

def isPureRef(tree: tpd.Tree)(implicit ctx: Context) =
refPurity(tree) == Pure
def isIdempotentRef(tree: tpd.Tree)(implicit ctx: Context) =
tree.symbol.isStable || !tree.tpe.widen.isParameterless
refPurity(tree) >= Idempotent

/** Is symbol potentially a getter of a mutable variable?
*/
Expand Down Expand Up @@ -456,6 +476,15 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
case nil =>
Nil
}

private class PurityLevel(val x: Int) {
def >= (that: PurityLevel) = x >= that.x
def min(that: PurityLevel) = new PurityLevel(x min that.x)
}

private val Pure = new PurityLevel(2)
private val Idempotent = new PurityLevel(1)
private val Impure = new PurityLevel(0)
}

/** a Match(Typed(_, tpt), _) must be translated into a switch if isSwitchAnnotation(tpt.tpe)
Expand Down
3 changes: 3 additions & 0 deletions src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ object Trees {
type ThisTree[-T >: Untyped] <: DenotingTree[T]
override def denot(implicit ctx: Context) = tpe match {
case tpe: NamedType => tpe.denot
case ThisType(cls) => cls.denot
case _ => NoDenotation
}
}
Expand Down Expand Up @@ -1162,6 +1163,8 @@ object Trees {
cpy.Alternative(tree, transform(trees))
case UnApply(fun, implicits, patterns) =>
cpy.UnApply(tree, transform(fun), transform(implicits), transform(patterns))
case EmptyValDef =>
tree
case ValDef(mods, name, tpt, rhs) =>
cpy.ValDef(tree, mods, name, transform(tpt), transform(rhs))
case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
Expand Down
Loading