Skip to content

Commit fae2c3f

Browse files
committed
Merge pull request #122 from dotty-staging/transform/nullarify
Transform/nullarify
2 parents 732a690 + d3adfd7 commit fae2c3f

18 files changed

+231
-31
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,14 @@ class Compiler {
2020
def phases: List[List[Phase]] =
2121
List(
2222
List(new FrontEnd),
23-
List(new LazyValsCreateCompanionObjects, new TailRec), //force separataion between lazyVals and LVCreateCO
24-
List(new PatternMatcher, new LazyValTranformContext().transformer,
25-
new Splitter, new TypeTestsCasts, new InterceptedMethods),
23+
List(new LazyValsCreateCompanionObjects,
24+
new TailRec), //force separataion between lazyVals and LVCreateCO
25+
List(new PatternMatcher,
26+
new LazyValTranformContext().transformer,
27+
new Splitter),
28+
List(new Nullarify,
29+
new TypeTestsCasts,
30+
new InterceptedMethods),
2631
List(new Erasure),
2732
List(new UncurryTreeTransform)
2833
)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ object Trees {
639639

640640
/** => T */
641641
case class ByNameTypeTree[-T >: Untyped] private[ast] (result: Tree[T])
642-
extends Tree[T] {
642+
extends TypTree[T] {
643643
type ThisTree[-T >: Untyped] = ByNameTypeTree[T]
644644
}
645645

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
3030

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

3535
def SelectWithSig(qualifier: Tree, name: Name, sig: Signature)(implicit ctx: Context) =
3636
untpd.SelectWithSig(qualifier, name, sig)

src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,8 @@ class Definitions {
341341

342342
lazy val AbstractFunctionClass = mkArityArray("scala.runtime.AbstractFunction", MaxFunctionArity, 0)
343343
lazy val FunctionClass = mkArityArray("scala.Function", MaxFunctionArity, 0)
344+
lazy val Function0_apply = FunctionClass(0).requiredMethod(nme.apply)
345+
344346
lazy val TupleClass = mkArityArray("scala.Tuple", MaxTupleArity, 2)
345347
lazy val ProductNClass = mkArityArray("scala.Product", MaxTupleArity, 2)
346348

@@ -357,6 +359,7 @@ class Definitions {
357359

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

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

@@ -440,7 +443,7 @@ class Definitions {
440443
LongClass,
441444
FloatClass,
442445
DoubleClass)
443-
446+
444447
lazy val ScalaValueClasses: collection.Set[Symbol] = ScalaNumericValueClasses + UnitClass + BooleanClass
445448

446449
lazy val ScalaBoxedClasses = ScalaValueClasses map boxedClass

src/dotty/tools/dotc/core/DenotTransformers.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Periods._
55
import SymDenotations._
66
import Contexts._
77
import Types._
8+
import Symbols._
89
import Denotations._
910
import Phases._
1011
import java.lang.AssertionError
@@ -30,4 +31,19 @@ object DenotTransformers {
3031
/** The transformation method */
3132
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation
3233
}
34+
35+
trait InfoTransformer extends DenotTransformer {
36+
37+
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type
38+
39+
/** The transformation method */
40+
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = {
41+
val info1 = transformInfo(ref.info, ref.symbol)
42+
if (info1 eq ref.info) ref
43+
else ref match {
44+
case ref: SymDenotation => ref.copySymDenotation(info = info1)
45+
case _ => ref.derivedSingleDenotation(ref.symbol, info1)
46+
}
47+
}
48+
}
3349
}

src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ object Denotations {
512512
def current(implicit ctx: Context): SingleDenotation = {
513513
val currentPeriod = ctx.period
514514
val valid = myValidFor
515-
assert(valid.code > 0, s"negative period $valid: ${valid.code}")
515+
assert(valid.code > 0)
516516

517517
if (valid.runId != currentPeriod.runId) bringForward.current
518518
else {

src/dotty/tools/dotc/core/Types.scala

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,12 @@ object Types {
352352
goThis(tp)
353353
case tp: TypeRef =>
354354
tp.denot.findMember(name, pre, excluded)
355+
case tp: TermRef =>
356+
go (tp.underlying match {
357+
case mt: MethodType
358+
if mt.paramTypes.isEmpty && (tp.symbol is Stable) => mt.resultType
359+
case tp1 => tp1
360+
})
355361
case tp: TypeProxy =>
356362
go(tp.underlying)
357363
case tp: ClassInfo =>
@@ -449,7 +455,7 @@ object Types {
449455
final def implicitMembers(implicit ctx: Context): List[TermRef] = track("implicitMembers") {
450456
memberDenots(implicitFilter,
451457
(name, buf) => buf ++= member(name).altsWith(_ is Implicit))
452-
.toList.map(_.termRefWithSig)
458+
.toList.map(d => TermRef.withSig(this, d.symbol.asTerm))
453459
}
454460

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

1104-
protected def loadDenot(implicit ctx: Context) = {
1110+
protected def loadDenot(implicit ctx: Context): Denotation = {
11051111
val d =
11061112
if (name.isInheritedName) prefix.nonPrivateMember(name.revertInherited)
11071113
else prefix.member(name)
1108-
if (d.exists || ctx.phaseId == FirstPhaseId)
1114+
if (d.exists || ctx.phaseId == FirstPhaseId || !lastDenotation.isInstanceOf[SymDenotation])
11091115
d
11101116
else {// name has changed; try load in earlier phase and make current
1111-
val d = denot(ctx.withPhase(ctx.phaseId - 1)).current
1117+
val d = loadDenot(ctx.withPhase(ctx.phaseId - 1)).current
11121118
if (d.exists) d
11131119
else throw new Error(s"failure to reload $this")
11141120
}
@@ -1311,7 +1317,7 @@ object Types {
13111317
if (prefix eq NoPrefix) withNonMemberSym(prefix, name, sym)
13121318
else {
13131319
if (sym.defRunId != NoRunId && sym.isCompleted) withSig(prefix, name, sym.signature)
1314-
else apply(prefix, name)
1320+
else apply(prefix, name)
13151321
} withSym (sym, Signature.NotAMethod)
13161322

13171323
def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef =

src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,14 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
5454
}
5555

5656
override def toTextPrefix(tp: Type): Text = controlled {
57+
def isOmittable(sym: Symbol) = isOmittablePrefix(sym) && !ctx.settings.verbose.value
5758
tp match {
5859
case ThisType(cls) =>
59-
if (isOmittablePrefix(cls)) return ""
60+
if (isOmittable(cls)) return ""
6061
case tp @ TermRef(pre, _) =>
6162
val sym = tp.symbol
6263
if (sym.isPackageObject) return toTextPrefix(pre)
63-
if (isOmittablePrefix(sym)) return ""
64+
if (isOmittable(sym)) return ""
6465
case _ =>
6566
}
6667
super.toTextPrefix(tp)

src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class Erasure extends Phase with DenotTransformer {
2828
override def name: String = "erasure"
2929

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

3333
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
3434
case ref: SymDenotation =>

src/dotty/tools/dotc/transform/InterceptedMethods.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package dotty.tools.dotc
22
package transform
33

44
import TreeTransforms._
5-
import core.DenotTransformers._
65
import core.Denotations._
76
import core.SymDenotations._
87
import core.Contexts._
@@ -27,7 +26,6 @@ import dotty.runtime.LazyVals
2726
import scala.collection.mutable.ListBuffer
2827
import dotty.tools.dotc.core.Denotations.SingleDenotation
2928
import dotty.tools.dotc.core.SymDenotations.SymDenotation
30-
import dotty.tools.dotc.core.DenotTransformers.DenotTransformer
3129
import StdNames._
3230

3331
/** Replace member references as follows:

src/dotty/tools/dotc/transform/LazyVals.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ class LazyValTranformContext {
6868
override def runsAfterGroupsOf: Set[String] = Set("lazyValsModules")
6969
/** List of names of phases that should have finished their processing of all compilation units
7070
* before this phase starts */
71-
override def runsAfter: Set[String] = Set("lazyValsModules")
7271

7372
/** List of names of phases that should have finished processing of tree
7473
* before this phase starts processing same tree */
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import TreeTransforms._
5+
import core.DenotTransformers._
6+
import core.Symbols._
7+
import core.Contexts._
8+
import core.Types._
9+
import core.Flags._
10+
import core.Decorators._
11+
import core.StdNames.nme
12+
import ast.Trees._
13+
14+
/** This phase eliminates ExprTypes `=> T` and PolyTypes over value types `[X]T`.
15+
* They are expressed in terms of nullary method or function types. More precisely:
16+
*
17+
* For types:
18+
*
19+
* => T ==> () => T if T is the type of a parameter
20+
* ==> ()T otherwise
21+
* [X]T ==> [X]()T
22+
*
23+
* For definitions:
24+
*
25+
* def f: R ==> def f(): R
26+
* def f[X]: R ==> def f[X](): R
27+
* (x: => T) ==> (x: () => T)
28+
*
29+
* For terms:
30+
*
31+
* f ==> f() if f had type => T and is not a parameter
32+
* x ==> x.apply() if x is a parameter that had type => T
33+
* e.apply() ==> e if e.apply() is an argument to a call-by-name parameter
34+
* expr ==> () => expr if other expr is an argument to a call-by-name parameter
35+
*
36+
*/
37+
class Nullarify extends TreeTransform with InfoTransformer {
38+
import ast.tpd._
39+
40+
override def name: String = "nullarify"
41+
42+
override def runsAfterGroupsOf: Set[String] = Set("splitter")
43+
// assumes idents and selects have symbols; interferes with splitter distribution
44+
// that's why it's "after group".
45+
46+
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
47+
ctx.traceIndented(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) {
48+
49+
def transformArg(arg: Tree, formal: Type): Tree = formal match {
50+
case _: ExprType =>
51+
arg match {
52+
case Apply(Select(qual, nme.apply), Nil) if qual.tpe <:< defn.FunctionClass(0).typeRef => qual
53+
case _ =>
54+
val meth = ctx.newSymbol(ctx.owner, nme.ANON_FUN, Synthetic,
55+
MethodType(Nil, Nil, arg.tpe.widen))
56+
Closure(meth, _ => arg)
57+
}
58+
case _ =>
59+
arg
60+
}
61+
62+
// Compute the method type tree had before this phase is run.
63+
// This is needed to find out which parameters are by-name.
64+
val funType = tree.fun.symbol.info match {
65+
case info: PolyType => info.resultType
66+
case info => info
67+
}
68+
def methType(info: Type, tree: Tree): Type = tree match {
69+
case Apply(fn, args) => methType(info.resultType, fn)
70+
case _ => info
71+
}
72+
val MethodType(_, formals) = methType(funType, tree.fun)
73+
74+
val args1 = tree.args.zipWithConserve(formals)(transformArg)
75+
cpy.Apply(tree, tree.fun, args1) withType nullarify(tree.tpe)
76+
}
77+
78+
/** Insert () or .apply() if the term refers to something that was converted to a
79+
* nullary method. Also, transform its type.
80+
*/
81+
def insertParens(tree: Tree)(implicit ctx: Context): Tree = {
82+
val tp1 = transformInfo(tree.tpe, tree.symbol)
83+
val tree1 = tree.withType(tp1)
84+
val origType = tree.tpe.widenSingleton
85+
def result(implicit ctx: Context) = {
86+
tp1.widen match {
87+
case MethodType(Nil, _) if origType.widenExpr.isInstanceOf[ValueType] =>
88+
Apply(tree1, Nil)
89+
case _ =>
90+
origType match {
91+
case _: ExprType => // it's a by-name parameter
92+
Apply(Select(tree1, defn.Function0_apply), Nil)
93+
case _ =>
94+
tree1
95+
}
96+
}
97+
}
98+
result(ctx.withPhase(ctx.phase.next))
99+
}
100+
101+
override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree =
102+
insertParens(tree)
103+
104+
override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree =
105+
insertParens(tree)
106+
107+
override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree =
108+
insertParens(tree)
109+
110+
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
111+
val DefDef(mods, name, tparams, vparamss, tpt, rhs) = tree
112+
val vparamss1 =
113+
if (vparamss.isEmpty) Nil :: Nil
114+
else vparamss nestedMap { vparam =>
115+
val tp = vparam.tpt.tpe
116+
val tp1 = nullarifyParam(tp)
117+
if (tp eq tp1) vparam
118+
else cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt.withType(tp1), vparam.rhs)
119+
}
120+
cpy.DefDef(tree, mods, name, tparams, vparamss1, tpt, rhs)
121+
}
122+
123+
def nullarify(tp: Type)(implicit ctx: Context): Type = tp match {
124+
case ExprType(rt) =>
125+
MethodType(Nil, Nil, rt)
126+
case pt: PolyType =>
127+
val rt = pt.resultType match {
128+
case mt: MethodType => nullarify(mt)
129+
case rt => MethodType(Nil, Nil, rt)
130+
}
131+
pt.derivedPolyType(pt.paramNames, pt.paramBounds, rt)
132+
case mt: MethodType =>
133+
mt.derivedMethodType(mt.paramNames, mt.paramTypes mapConserve nullarifyParam,
134+
nullarify(mt.resultType))
135+
case _ =>
136+
tp
137+
}
138+
139+
def nullarifyParam(tp: Type)(implicit ctx: Context) = tp match {
140+
case ExprType(rt) => defn.FunctionType(Nil, rt)
141+
case _ => tp
142+
}
143+
144+
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
145+
if (defn.typeTestsOrCasts contains sym) tp
146+
else if (sym is Param) nullarifyParam(tp)
147+
else nullarify(tp)
148+
}

src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package dotty.tools.dotc
22
package transform
33

44
import TreeTransforms._
5-
import core.DenotTransformers._
65
import core.Denotations._
76
import core.SymDenotations._
87
import core.Contexts._

src/dotty/tools/dotc/transform/TypeTestsCasts.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package dotty.tools.dotc
22
package transform
33

44
import TreeTransforms._
5-
import core.DenotTransformers._
65
import core.Denotations._
76
import core.SymDenotations._
87
import core.Contexts._

src/dotty/tools/dotc/transform/UncurryTreeTransform.scala

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import core.Denotations._
77
import core.SymDenotations._
88
import core.Contexts._
99
import core.Types._
10+
import core.Symbols._
1011
import ast.Trees._
1112
import ast.tpd.{Apply, Tree, cpy}
1213

13-
class UncurryTreeTransform extends TreeTransform with DenotTransformer {
14+
class UncurryTreeTransform extends TreeTransform with InfoTransformer {
1415

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

43-
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = {
44-
val info1 = uncurry(ref.info)
45-
if (info1 eq ref.info) ref
46-
else ref match {
47-
case ref: SymDenotation => ref.copySymDenotation(info = info1)
48-
case _ => ref.derivedSingleDenotation(ref.symbol, info1)
49-
}
50-
}
44+
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
45+
uncurry(tp)
5146
}

0 commit comments

Comments
 (0)