Skip to content

Commit 3392ef7

Browse files
committed
Merge pull request #493 from dotty-staging/fix-modules
Make LazyVals implement non-static modules. Move LV after erasure.
2 parents cf7c245 + d23e71a commit 3392ef7

24 files changed

+256
-185
lines changed

project/Build.scala

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ import java.nio.channels.FileLock
55

66
object DottyBuild extends Build {
77

8+
val travisMemLimit = List("-Xmx1g", "-Xss2m")
9+
810
val TRAVIS_BUILD = "dotty.travis.build"
911

1012
val agentOptions = List(
1113
// "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"
1214
// "-agentpath:/home/dark/opt/yjp-2013-build-13072/bin/linux-x86-64/libyjpagent.so"
15+
// "-agentpath:/Applications/YourKit_Java_Profiler_2015_build_15052.app/Contents/Resources/bin/mac/libyjpagent.jnilib",
16+
// "-XX:+HeapDumpOnOutOfMemoryError", "-Xmx1g", "-Xss2m"
1317
)
1418

1519
var partestLock: FileLock = null
@@ -79,7 +83,7 @@ object DottyBuild extends Build {
7983

8084
val travis_build = // propagate if this is a travis build
8185
if (sys.props.isDefinedAt(TRAVIS_BUILD))
82-
List(s"-D$TRAVIS_BUILD=${sys.props(TRAVIS_BUILD)}")
86+
List(s"-D$TRAVIS_BUILD=${sys.props(TRAVIS_BUILD)}") ::: travisMemLimit
8387
else
8488
List()
8589

src/dotty/runtime/LazyVals.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ object LazyVals {
1111
final val BITS_PER_LAZY_VAL = 2
1212
final val LAZY_VAL_MASK = 3
1313

14-
@inline def STATE(cur: Long, ord: Long) = (cur >> (ord * BITS_PER_LAZY_VAL)) & LAZY_VAL_MASK
15-
@inline def CAS(t: Object, offset: Long, e: Long, v: Long, ord: Int) = {
14+
@inline def STATE(cur: Long, ord: Int) = (cur >> (ord * BITS_PER_LAZY_VAL)) & LAZY_VAL_MASK
15+
@inline def CAS(t: Object, offset: Long, e: Long, v: Int, ord: Int) = {
1616
val mask = ~(LAZY_VAL_MASK << ord * BITS_PER_LAZY_VAL)
1717
val n = (e & mask) | (v << (ord * BITS_PER_LAZY_VAL))
1818
compareAndSet(t, offset, e, n)
@@ -65,7 +65,7 @@ object LazyVals {
6565
monitors(id)
6666
}
6767

68-
@inline def getOffset(obj: Object, name: String) = unsafe.objectFieldOffset(obj.getClass.getDeclaredField(name))
68+
@inline def getOffset(clz: Class[_], name: String) = unsafe.objectFieldOffset(clz.getDeclaredField(name))
6969

7070
object Names {
7171
final val state = "STATE"

src/dotty/tools/backend/jvm/DottyBackendInterface.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{
589589
def isDeferred: Boolean = sym is Flags.Deferred
590590
def isPrivate: Boolean = sym is Flags.Private
591591
def getsJavaFinalFlag: Boolean =
592-
isFinal && !toDenot(sym).isClassConstructor && !(sym is Flags.Mutable) && !(sym.enclosingClass is Flags.JavaInterface)
592+
isFinal && !toDenot(sym).isClassConstructor && !(sym is Flags.Mutable) && !(sym.enclosingClass is Flags.Trait)
593593

594594
def getsJavaPrivateFlag: Boolean =
595595
isPrivate //|| (sym.isPrimaryConstructor && sym.owner.isTopLevelModuleClass)

src/dotty/tools/dotc/Compiler.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,20 @@ class Compiler {
4949
List(new PatternMatcher,
5050
new ExplicitOuter,
5151
new Splitter),
52-
List(new LazyVals,
53-
new SeqLiterals,
52+
List(new SeqLiterals,
5453
new InterceptedMethods,
5554
new Literalize,
5655
new Getters,
5756
new ElimByName,
5857
new ResolveSuper),
5958
List(new Erasure),
6059
List(new Mixin,
60+
new LazyVals,
6161
new Memoize,
62-
new CapturedVars,
62+
new CapturedVars, // capturedVars has a transformUnit: no phases should introduce local mutable vars here
6363
new Constructors,
6464
new FunctionalInterfaces),
65-
List(new LambdaLift,
65+
List(new LambdaLift, // in this mini-phase block scopes are incorrect. No phases that rely on scopes should be here
6666
new Flatten,
6767
new RestoreScopes),
6868
List(/*new PrivateToStatic,*/ new CollectEntryPoints, new LabelDefs, new ElimWildcardIdents, new TraitConstructors),

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

+28-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dotty.tools
22
package dotc
33
package ast
44

5+
import dotty.tools.dotc.transform.ExplicitOuter
56
import dotty.tools.dotc.typer.ProtoTypes.FunProtoTyped
67
import transform.SymUtils._
78
import core._
@@ -243,6 +244,17 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
243244
ta.assignType(untpd.TypeDef(cls.name, impl), cls)
244245
}
245246

247+
// { <label> def while$(): Unit = if (cond) { body; while$() } ; while$() }
248+
def WhileDo(owner: Symbol, cond: Tree, body: List[Tree])(implicit ctx: Context): Tree = {
249+
val sym = ctx.newSymbol(owner, nme.WHILE_PREFIX, Flags.Label | Flags.Synthetic,
250+
MethodType(Nil, defn.UnitType), coord = cond.pos)
251+
252+
val call = Apply(ref(sym), Nil)
253+
val rhs = If(cond, Block(body, call), unitLiteral)
254+
Block(List(DefDef(sym, rhs)), call)
255+
}
256+
257+
246258
def Import(expr: Tree, selectors: List[untpd.Tree])(implicit ctx: Context): Import =
247259
ta.assignType(untpd.Import(expr, selectors), ctx.newImportSymbol(ctx.owner, expr))
248260

@@ -288,7 +300,16 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
288300
if (tp.isType) TypeTree(tp)
289301
else if (prefixIsElidable(tp)) Ident(tp)
290302
else tp.prefix match {
291-
case pre: SingletonType => singleton(pre).select(tp)
303+
case pre: SingletonType =>
304+
val prefix =
305+
singleton(pre) match {
306+
case t: This if ctx.erasedTypes && !(t.symbol == ctx.owner.enclosingClass || t.symbol.isStaticOwner) =>
307+
// after erasure outer paths should be respected
308+
new ExplicitOuter.OuterOps(ctx).path(t.tpe.widen.classSymbol)
309+
case t =>
310+
t
311+
}
312+
prefix.select(tp)
292313
case pre => SelectFromTypeTree(TypeTree(pre), tp)
293314
} // no checks necessary
294315

@@ -563,7 +584,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
563584
loop(from.owner, from :: froms, to :: tos)
564585
else {
565586
//println(i"change owner ${from :: froms}%, % ==> $tos of $tree")
566-
new TreeTypeMap(oldOwners = from :: froms, newOwners = tos).apply(tree)
587+
new TreeTypeMap(oldOwners = from :: froms, newOwners = tos)(ctx.withMode(Mode.FutureDefsOK)).apply(tree)
567588
}
568589
}
569590
loop(from, Nil, to :: Nil)
@@ -578,8 +599,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
578599
def traverse(tree: Tree)(implicit ctx: Context) = tree match {
579600
case tree: DefTree =>
580601
val sym = tree.symbol
581-
if (sym.denot(ctx.withPhase(trans)).owner == from)
582-
sym.copySymDenotation(owner = to).installAfter(trans)
602+
if (sym.denot(ctx.withPhase(trans)).owner == from) {
603+
val d = sym.copySymDenotation(owner = to)
604+
d.installAfter(trans)
605+
d.transformAfter(trans, d => if (d.owner eq from) d.copySymDenotation(owner = to) else d)
606+
}
583607
if (sym.isWeakOwner) traverseChildren(tree)
584608
case _ =>
585609
traverseChildren(tree)

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

+30-8
Original file line numberDiff line numberDiff line change
@@ -620,14 +620,9 @@ object Denotations {
620620
// println(s"installing $this after $phase/${phase.id}, valid = ${current.validFor}")
621621
// printPeriods(current)
622622
this.validFor = Period(ctx.runId, targetId, current.validFor.lastPhaseId)
623-
if (current.validFor.firstPhaseId == targetId) {
624-
// replace current with this denotation
625-
var prev = current
626-
while (prev.nextInRun ne current) prev = prev.nextInRun
627-
prev.nextInRun = this
628-
this.nextInRun = current.nextInRun
629-
current.validFor = Nowhere
630-
} else {
623+
if (current.validFor.firstPhaseId == targetId)
624+
replaceDenotation(current)
625+
else {
631626
// insert this denotation after current
632627
current.validFor = Period(ctx.runId, current.validFor.firstPhaseId, targetId - 1)
633628
this.nextInRun = current.nextInRun
@@ -637,6 +632,33 @@ object Denotations {
637632
}
638633
}
639634

635+
/** Apply a transformation `f` to all denotations in this group that start at or after
636+
* given phase. Denotations are replaced while keeping the same validity periods.
637+
*/
638+
protected def transformAfter(phase: DenotTransformer, f: SymDenotation => SymDenotation)(implicit ctx: Context): Unit = {
639+
var current = symbol.current
640+
while (current.validFor.firstPhaseId < phase.id && (current.nextInRun.validFor.code > current.validFor.code))
641+
current = current.nextInRun
642+
var hasNext = true
643+
while ((current.validFor.firstPhaseId >= phase.id) && hasNext) {
644+
val current1: SingleDenotation = f(current.asSymDenotation)
645+
if (current1 ne current) {
646+
current1.validFor = current.validFor
647+
current1.replaceDenotation(current)
648+
}
649+
hasNext = current1.nextInRun.validFor.code > current1.validFor.code
650+
current = current1.nextInRun
651+
}
652+
}
653+
654+
private def replaceDenotation(current: SingleDenotation): Unit = {
655+
var prev = current
656+
while (prev.nextInRun ne current) prev = prev.nextInRun
657+
prev.nextInRun = this
658+
this.nextInRun = current.nextInRun
659+
current.validFor = Nowhere
660+
}
661+
640662
def staleSymbolError(implicit ctx: Context) = {
641663
def ownerMsg = this match {
642664
case denot: SymDenotation => s"in ${denot.owner}"

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

+6
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,12 @@ object SymDenotations {
10431043
/** Install this denotation as the result of the given denotation transformer. */
10441044
override def installAfter(phase: DenotTransformer)(implicit ctx: Context): Unit =
10451045
super.installAfter(phase)
1046+
1047+
/** Apply a transformation `f` to all denotations in this group that start at or after
1048+
* given phase. Denotations are replaced while keeping the same validity periods.
1049+
*/
1050+
override def transformAfter(phase: DenotTransformer, f: SymDenotation => SymDenotation)(implicit ctx: Context): Unit =
1051+
super.transformAfter(phase, f)
10461052
}
10471053

10481054
/** The contents of a class definition during a period

src/dotty/tools/dotc/core/pickling/NameBuffer.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import scala.io.Codec
1111
import TastyName._
1212
import PickleFormat._
1313

14-
class NameBuffer extends TastyBuffer(100000) {
14+
class NameBuffer extends TastyBuffer(10000) {
1515

1616
private val nameRefs = new mutable.LinkedHashMap[TastyName, NameRef]
1717

src/dotty/tools/dotc/core/pickling/PositionPickler.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ object PositionPickler {
3838
import PositionPickler._
3939

4040
class PositionPickler(pickler: TastyPickler, addrOfTree: Tree => Option[Addr]) {
41-
val buf = new TastyBuffer(100000)
41+
val buf = new TastyBuffer(5000)
4242
pickler.newSection("Positions", buf)
4343
import buf._
4444

src/dotty/tools/dotc/core/pickling/TastyBuffer.scala

+4-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ class TastyBuffer(initialSize: Int) {
4444

4545
/** Write a byte of data. */
4646
def writeByte(b: Int): Unit = {
47-
if (length == bytes.length) bytes = dble(bytes)
47+
if (length >= bytes.length)
48+
bytes = dble(bytes)
4849
bytes(length) = b.toByte
4950
length += 1
5051
}
@@ -116,6 +117,8 @@ class TastyBuffer(initialSize: Int) {
116117
def putNat(at: Addr, x: Int, width: Int): Unit = {
117118
var y = x
118119
var w = width
120+
if(at.index + w >= bytes.length)
121+
bytes = dble(bytes)
119122
var digit = y & 0x7f | 0x80
120123
while (w > 0) {
121124
w -= 1

src/dotty/tools/dotc/core/pickling/TreeBuffer.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@ import TastyBuffer.{Addr, AddrWidth}
88
import config.Printers.pickling
99
import ast.tpd.Tree
1010

11-
class TreeBuffer extends TastyBuffer(1000000) {
11+
class TreeBuffer extends TastyBuffer(50000) {
1212

1313
private final val ItemsOverOffsets = 2
14-
1514
private val initialOffsetSize = bytes.length / (AddrWidth * ItemsOverOffsets)
1615
private var offsets = new Array[Int](initialOffsetSize)
1716
private var isRelative = new Array[Boolean](initialOffsetSize)

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

+6-8
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,10 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
8080
// (2) If the parameter accessor reference was to an alias getter,
8181
// drop the () when replacing by the parameter.
8282
object intoConstr extends TreeMap {
83-
private var excluded: FlagSet = _
8483
override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match {
8584
case Ident(_) | Select(This(_), _) =>
8685
var sym = tree.symbol
87-
if (sym is (ParamAccessor, butNot = excluded)) sym = sym.subst(accessors, paramSyms)
86+
if (sym is (ParamAccessor, butNot = Mutable)) sym = sym.subst(accessors, paramSyms)
8887
if (sym.owner.isConstructor) ref(sym).withPos(tree.pos) else tree
8988
case Apply(fn, Nil) =>
9089
val fn1 = transform(fn)
@@ -95,9 +94,8 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
9594
if (noDirectRefsFrom(tree)) tree else super.transform(tree)
9695
}
9796

98-
def apply(tree: Tree, inSuperCall: Boolean = false)(implicit ctx: Context): Tree = {
99-
this.excluded = if (inSuperCall) EmptyFlags else Mutable
100-
transform(tree)
97+
def apply(tree: Tree, prevOwner: Symbol)(implicit ctx: Context): Tree = {
98+
transform(tree).changeOwnerAfter(prevOwner, constr.symbol, thisTransform)
10199
}
102100
}
103101

@@ -153,19 +151,19 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
153151
val sym = stat.symbol
154152
if (isRetained(sym)) {
155153
if (!stat.rhs.isEmpty && !isWildcardArg(stat.rhs))
156-
constrStats += Assign(ref(sym), intoConstr(stat.rhs)).withPos(stat.pos)
154+
constrStats += Assign(ref(sym), intoConstr(stat.rhs, sym)).withPos(stat.pos)
157155
clsStats += cpy.ValDef(stat)(rhs = EmptyTree)
158156
}
159157
else if (!stat.rhs.isEmpty) {
160158
sym.copySymDenotation(
161159
initFlags = sym.flags &~ Private,
162160
owner = constr.symbol).installAfter(thisTransform)
163-
constrStats += intoConstr(stat)
161+
constrStats += intoConstr(stat, sym)
164162
}
165163
case _: DefTree =>
166164
clsStats += stat
167165
case _ =>
168-
constrStats += intoConstr(stat)
166+
constrStats += intoConstr(stat, tree.symbol)
169167
}
170168
splitStats(stats1)
171169
case Nil =>

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,8 @@ object Erasure extends TypeTestsCasts{
502502

503503
traverse(newStats, oldStats)
504504
}
505+
506+
private final val NoBridgeFlags = Flags.Accessor | Flags.Deferred | Flags.Lazy
505507

506508
/** Create a bridge DefDef which overrides a parent method.
507509
*
@@ -520,7 +522,7 @@ object Erasure extends TypeTestsCasts{
520522
???
521523
}
522524
val bridge = ctx.newSymbol(currentClass,
523-
parentSym.name, parentSym.flags | Flags.Bridge, parentSym.info, coord = newDefSym.owner.coord).asTerm
525+
parentSym.name, parentSym.flags &~ NoBridgeFlags | Flags.Bridge, parentSym.info, coord = newDefSym.owner.coord).asTerm
524526
bridge.enteredAfter(ctx.phase.prev.asInstanceOf[DenotTransformer]) // this should be safe, as we're executing in context of next phase
525527
ctx.debuglog(s"generating bridge from ${newDefSym} to $bridge")
526528

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import collection.mutable
2828
*
2929
* - add outer parameters to constructors
3030
* - pass outer arguments in constructor calls
31-
* - replace outer this by outer paths.
3231
*
32+
* replacement of outer this by outer paths is done in Erasure.
3333
* needs to run after pattern matcher as it can add outer checks and force creation of $outer
3434
*/
3535
class ExplicitOuter extends MiniPhaseTransform with InfoTransformer { thisTransformer =>

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

+13-7
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,21 @@ import Decorators._
1616
/** Performs the following rewritings for fields of a class:
1717
*
1818
* <mods> val x: T = e
19-
* --> <mods> <stable> def x: T = e
19+
* --> <mods> <stable> <accessor> def x: T = e
2020
* <mods> var x: T = e
21-
* --> <mods> def x: T = e
21+
* --> <mods> <accessor> def x: T = e
2222
*
2323
* <mods> val x: T
24-
* --> <mods> <stable> def x: T
24+
* --> <mods> <stable> <accessor> def x: T
25+
*
26+
* <mods> lazy val x: T = e
27+
* --> <mods> <accessor> lazy def x: T =e
2528
*
2629
* <mods> var x: T
27-
* --> <mods> def x: T
30+
* --> <mods> <accessor> def x: T
31+
*
32+
* <mods> non-static <module> val x$ = e
33+
* --> <mods> <module> <accessor> def x$ = e
2834
*
2935
* Omitted from the rewritings are
3036
*
@@ -47,18 +53,18 @@ class Getters extends MiniPhaseTransform with SymTransformer { thisTransform =>
4753
override def transformSym(d: SymDenotation)(implicit ctx: Context): SymDenotation = {
4854
def noGetterNeeded =
4955
d.is(NoGetterNeeded) ||
50-
d.initial.asInstanceOf[SymDenotation].is(PrivateLocal) && !d.owner.is(Trait) ||
56+
d.initial.asInstanceOf[SymDenotation].is(PrivateLocal) && !d.owner.is(Trait) && !d.is(Flags.Lazy) ||
5157
d.is(Module) && d.isStatic ||
5258
d.isSelfSym
53-
if (d.isTerm && d.owner.isClass && d.info.isValueType && !noGetterNeeded) {
59+
if (d.isTerm && (d.is(Lazy) || d.owner.isClass) && d.info.isValueType && !noGetterNeeded) {
5460
val maybeStable = if (d.isStable) Stable else EmptyFlags
5561
d.copySymDenotation(
5662
initFlags = d.flags | maybeStable | AccessorCreationFlags,
5763
info = ExprType(d.info))
5864
}
5965
else d
6066
}
61-
private val NoGetterNeeded = Method | Param | JavaDefined | JavaStatic | Lazy
67+
private val NoGetterNeeded = Method | Param | JavaDefined | JavaStatic
6268

6369
override def transformValDef(tree: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree =
6470
if (tree.symbol is Method) DefDef(tree.symbol.asTerm, tree.rhs) else tree

0 commit comments

Comments
 (0)