Skip to content

Transform/nullarify #122

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 7 commits into from
Apr 15, 2014
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: 8 additions & 3 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ class Compiler {
def phases: List[List[Phase]] =
List(
List(new FrontEnd),
List(new LazyValsCreateCompanionObjects, new TailRec), //force separataion between lazyVals and LVCreateCO
List(new PatternMatcher, new LazyValTranformContext().transformer,
new Splitter, new TypeTestsCasts, new InterceptedMethods),
List(new LazyValsCreateCompanionObjects,
new TailRec), //force separataion between lazyVals and LVCreateCO
List(new PatternMatcher,
new LazyValTranformContext().transformer,
new Splitter),
List(new Nullarify,
Copy link
Contributor

Choose a reason for hiding this comment

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

What was a reason to create one more group?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's explained in class Nullarify:

override def runsAfterGroupsOf: Set[String] = Set("splitter")
  // assumes idents and selects have symbols; interferes with splitter distribution
  // that's why it's "after group".

new TypeTestsCasts,
new InterceptedMethods),
List(new Erasure),
List(new UncurryTreeTransform)
)
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ object Trees {

/** => T */
case class ByNameTypeTree[-T >: Untyped] private[ast] (result: Tree[T])
extends Tree[T] {
extends TypTree[T] {
type ThisTree[-T >: Untyped] = ByNameTypeTree[T]
}

Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {

def Select(qualifier: Tree, sym: Symbol)(implicit ctx: Context): Select =
untpd.Select(qualifier, sym.name).withType(
TermRef.withSig(qualifier.tpe, sym.name.asTermName, sym.signature, sym.denot))
TermRef.withSig(qualifier.tpe, sym.name.asTermName, sym.signature, sym.denot.asSeenFrom(qualifier.tpe)))

def SelectWithSig(qualifier: Tree, name: Name, sig: Signature)(implicit ctx: Context) =
untpd.SelectWithSig(qualifier, name, sig)
Expand Down
5 changes: 4 additions & 1 deletion src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,8 @@ class Definitions {

lazy val AbstractFunctionClass = mkArityArray("scala.runtime.AbstractFunction", MaxFunctionArity, 0)
lazy val FunctionClass = mkArityArray("scala.Function", MaxFunctionArity, 0)
lazy val Function0_apply = FunctionClass(0).requiredMethod(nme.apply)

lazy val TupleClass = mkArityArray("scala.Tuple", MaxTupleArity, 2)
lazy val ProductNClass = mkArityArray("scala.Product", MaxTupleArity, 2)

Expand All @@ -357,6 +359,7 @@ class Definitions {

lazy val asInstanceOfMethods = Set[Symbol](Any_asInstanceOf, Object_asInstanceOf)
lazy val isInstanceOfMethods = Set[Symbol](Any_isInstanceOf, Object_isInstanceOf)
lazy val typeTestsOrCasts = asInstanceOfMethods ++ isInstanceOfMethods

lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule)

Expand Down Expand Up @@ -440,7 +443,7 @@ class Definitions {
LongClass,
FloatClass,
DoubleClass)

lazy val ScalaValueClasses: collection.Set[Symbol] = ScalaNumericValueClasses + UnitClass + BooleanClass

lazy val ScalaBoxedClasses = ScalaValueClasses map boxedClass
Expand Down
16 changes: 16 additions & 0 deletions src/dotty/tools/dotc/core/DenotTransformers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Periods._
import SymDenotations._
import Contexts._
import Types._
import Symbols._
import Denotations._
import Phases._
import java.lang.AssertionError
Expand All @@ -30,4 +31,19 @@ object DenotTransformers {
/** The transformation method */
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation
}

trait InfoTransformer extends DenotTransformer {

def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type

/** The transformation method */
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = {
val info1 = transformInfo(ref.info, ref.symbol)
if (info1 eq ref.info) ref
else ref match {
case ref: SymDenotation => ref.copySymDenotation(info = info1)
case _ => ref.derivedSingleDenotation(ref.symbol, info1)
}
}
}
}
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ object Denotations {
def current(implicit ctx: Context): SingleDenotation = {
val currentPeriod = ctx.period
val valid = myValidFor
assert(valid.code > 0, s"negative period $valid: ${valid.code}")
assert(valid.code > 0)

if (valid.runId != currentPeriod.runId) bringForward.current
else {
Expand Down
16 changes: 11 additions & 5 deletions src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,12 @@ object Types {
goThis(tp)
case tp: TypeRef =>
tp.denot.findMember(name, pre, excluded)
case tp: TermRef =>
go (tp.underlying match {
case mt: MethodType
if mt.paramTypes.isEmpty && (tp.symbol is Stable) => mt.resultType
case tp1 => tp1
})
case tp: TypeProxy =>
go(tp.underlying)
case tp: ClassInfo =>
Expand Down Expand Up @@ -449,7 +455,7 @@ object Types {
final def implicitMembers(implicit ctx: Context): List[TermRef] = track("implicitMembers") {
memberDenots(implicitFilter,
(name, buf) => buf ++= member(name).altsWith(_ is Implicit))
.toList.map(_.termRefWithSig)
.toList.map(d => TermRef.withSig(this, d.symbol.asTerm))
}

/** The info of `sym`, seen as a member of this type. */
Expand Down Expand Up @@ -1101,14 +1107,14 @@ object Types {
private def withSig(sig: Signature)(implicit ctx: Context): NamedType =
TermRef.withSig(prefix, name.asTermName, sig)

protected def loadDenot(implicit ctx: Context) = {
protected def loadDenot(implicit ctx: Context): Denotation = {
val d =
if (name.isInheritedName) prefix.nonPrivateMember(name.revertInherited)
else prefix.member(name)
if (d.exists || ctx.phaseId == FirstPhaseId)
if (d.exists || ctx.phaseId == FirstPhaseId || !lastDenotation.isInstanceOf[SymDenotation])
d
else {// name has changed; try load in earlier phase and make current
val d = denot(ctx.withPhase(ctx.phaseId - 1)).current
val d = loadDenot(ctx.withPhase(ctx.phaseId - 1)).current
if (d.exists) d
else throw new Error(s"failure to reload $this")
}
Expand Down Expand Up @@ -1311,7 +1317,7 @@ object Types {
if (prefix eq NoPrefix) withNonMemberSym(prefix, name, sym)
else {
if (sym.defRunId != NoRunId && sym.isCompleted) withSig(prefix, name, sym.signature)
else apply(prefix, name)
else apply(prefix, name)
} withSym (sym, Signature.NotAMethod)

def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef =
Expand Down
5 changes: 3 additions & 2 deletions src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}

override def toTextPrefix(tp: Type): Text = controlled {
def isOmittable(sym: Symbol) = isOmittablePrefix(sym) && !ctx.settings.verbose.value
tp match {
case ThisType(cls) =>
if (isOmittablePrefix(cls)) return ""
if (isOmittable(cls)) return ""
case tp @ TermRef(pre, _) =>
val sym = tp.symbol
if (sym.isPackageObject) return toTextPrefix(pre)
if (isOmittablePrefix(sym)) return ""
if (isOmittable(sym)) return ""
case _ =>
}
super.toTextPrefix(tp)
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Erasure extends Phase with DenotTransformer {
override def name: String = "erasure"

/** List of names of phases that should precede this phase */
override def runsAfter: Set[String] = Set("typeTestsCasts", "intercepted", "splitter")
override def runsAfter: Set[String] = Set("typeTestsCasts", "intercepted", "splitter", "nullarify")

def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
case ref: SymDenotation =>
Expand Down
2 changes: 0 additions & 2 deletions src/dotty/tools/dotc/transform/InterceptedMethods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package dotty.tools.dotc
package transform

import TreeTransforms._
import core.DenotTransformers._
import core.Denotations._
import core.SymDenotations._
import core.Contexts._
Expand All @@ -27,7 +26,6 @@ import dotty.runtime.LazyVals
import scala.collection.mutable.ListBuffer
import dotty.tools.dotc.core.Denotations.SingleDenotation
import dotty.tools.dotc.core.SymDenotations.SymDenotation
import dotty.tools.dotc.core.DenotTransformers.DenotTransformer
import StdNames._

/** Replace member references as follows:
Expand Down
1 change: 0 additions & 1 deletion src/dotty/tools/dotc/transform/LazyVals.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ class LazyValTranformContext {
override def runsAfterGroupsOf: Set[String] = Set("lazyValsModules")
/** List of names of phases that should have finished their processing of all compilation units
* before this phase starts */
override def runsAfter: Set[String] = Set("lazyValsModules")

/** List of names of phases that should have finished processing of tree
* before this phase starts processing same tree */
Expand Down
148 changes: 148 additions & 0 deletions src/dotty/tools/dotc/transform/Nullarify.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
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 eliminates ExprTypes `=> T` and PolyTypes over value types `[X]T`.
* They are expressed in terms of nullary method or function types. More precisely:
*
* For types:
*
* => T ==> () => T if T is the type of a parameter
* ==> ()T otherwise
* [X]T ==> [X]()T
*
* For definitions:
*
* def f: R ==> def f(): R
* def f[X]: R ==> def f[X](): R
* (x: => T) ==> (x: () => T)
*
* For terms:
*
* f ==> f() if f had type => T and is not a parameter
* x ==> x.apply() if x is a parameter that had type => T
* e.apply() ==> e if e.apply() is an argument to a call-by-name parameter
* expr ==> () => expr if other expr is an argument to a call-by-name parameter
*
*/
class Nullarify extends TreeTransform with InfoTransformer {
import ast.tpd._

override def name: String = "nullarify"

override def runsAfterGroupsOf: Set[String] = Set("splitter")
// assumes idents and selects have symbols; interferes with splitter distribution
// that's why it's "after group".

override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
ctx.traceIndented(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) {

def transformArg(arg: Tree, formal: Type): Tree = formal match {
case _: ExprType =>
arg match {
case Apply(Select(qual, nme.apply), Nil) if qual.tpe <:< defn.FunctionClass(0).typeRef => qual
case _ =>
val meth = ctx.newSymbol(ctx.owner, nme.ANON_FUN, Synthetic,
MethodType(Nil, Nil, arg.tpe.widen))
Closure(meth, _ => arg)
}
case _ =>
arg
}

// Compute the method type tree had before this phase is run.
// This is needed to find out which parameters are by-name.
val funType = tree.fun.symbol.info match {
case info: PolyType => info.resultType
case info => info
}
def methType(info: Type, tree: Tree): Type = tree match {
case Apply(fn, args) => methType(info.resultType, fn)
case _ => info
}
val MethodType(_, formals) = methType(funType, tree.fun)

val args1 = tree.args.zipWithConserve(formals)(transformArg)
cpy.Apply(tree, tree.fun, args1) withType nullarify(tree.tpe)
}

/** Insert () or .apply() if the term refers to something that was converted to a
* nullary method. Also, transform its type.
*/
def insertParens(tree: Tree)(implicit ctx: Context): Tree = {
val tp1 = transformInfo(tree.tpe, tree.symbol)
val tree1 = tree.withType(tp1)
val origType = tree.tpe.widenSingleton
def result(implicit ctx: Context) = {
tp1.widen match {
case MethodType(Nil, _) if origType.widenExpr.isInstanceOf[ValueType] =>
Apply(tree1, Nil)
case _ =>
origType match {
case _: ExprType => // it's a by-name parameter
Apply(Select(tree1, defn.Function0_apply), Nil)
case _ =>
tree1
}
}
}
result(ctx.withPhase(ctx.phase.next))
}

override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree =
insertParens(tree)

override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree =
insertParens(tree)

override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree =
insertParens(tree)

override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
val DefDef(mods, name, tparams, vparamss, tpt, rhs) = tree
val vparamss1 =
if (vparamss.isEmpty) Nil :: Nil
else vparamss nestedMap { vparam =>
val tp = vparam.tpt.tpe
val tp1 = nullarifyParam(tp)
if (tp eq tp1) vparam
else cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt.withType(tp1), vparam.rhs)
}
cpy.DefDef(tree, mods, name, tparams, vparamss1, tpt, rhs)
}

def nullarify(tp: Type)(implicit ctx: Context): Type = tp match {
case ExprType(rt) =>
MethodType(Nil, Nil, rt)
case pt: PolyType =>
val rt = pt.resultType match {
case mt: MethodType => nullarify(mt)
case rt => MethodType(Nil, Nil, rt)
}
pt.derivedPolyType(pt.paramNames, pt.paramBounds, rt)
case mt: MethodType =>
mt.derivedMethodType(mt.paramNames, mt.paramTypes mapConserve nullarifyParam,
nullarify(mt.resultType))
case _ =>
tp
}

def nullarifyParam(tp: Type)(implicit ctx: Context) = tp match {
case ExprType(rt) => defn.FunctionType(Nil, rt)
case _ => tp
}

def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
if (defn.typeTestsOrCasts contains sym) tp
else if (sym is Param) nullarifyParam(tp)
else nullarify(tp)
}
1 change: 0 additions & 1 deletion src/dotty/tools/dotc/transform/PatternMatcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package dotty.tools.dotc
package transform

import TreeTransforms._
import core.DenotTransformers._
import core.Denotations._
import core.SymDenotations._
import core.Contexts._
Expand Down
1 change: 0 additions & 1 deletion src/dotty/tools/dotc/transform/TypeTestsCasts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package dotty.tools.dotc
package transform

import TreeTransforms._
import core.DenotTransformers._
import core.Denotations._
import core.SymDenotations._
import core.Contexts._
Expand Down
13 changes: 4 additions & 9 deletions src/dotty/tools/dotc/transform/UncurryTreeTransform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import core.Denotations._
import core.SymDenotations._
import core.Contexts._
import core.Types._
import core.Symbols._
import ast.Trees._
import ast.tpd.{Apply, Tree, cpy}

class UncurryTreeTransform extends TreeTransform with DenotTransformer {
class UncurryTreeTransform extends TreeTransform with InfoTransformer {

override def name: String = "uncurry"
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
Expand Down Expand Up @@ -40,12 +41,6 @@ class UncurryTreeTransform extends TreeTransform with DenotTransformer {
tp
}

def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = {
val info1 = uncurry(ref.info)
if (info1 eq ref.info) ref
else ref match {
case ref: SymDenotation => ref.copySymDenotation(info = info1)
case _ => ref.derivedSingleDenotation(ref.symbol, info1)
}
}
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
uncurry(tp)
}
Loading