Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ class Compiler {
new LazyVals, // Expand lazy vals
new Memoize, // Add private fields to getters and setters
new NonLocalReturns, // Expand non-local returns
new CapturedVars, // Represent vars captured by closures as heap objects
new Constructors, // Collect initialization code in primary constructors
new CapturedVars), // Represent vars captured by closures as heap objects
List(new Constructors, // Collect initialization code in primary constructors
// Note: constructors changes decls in transformTemplate, no InfoTransformers should be added after it
new FunctionalInterfaces, // Rewrites closures to implement @specialized types of Functions.
new GetClass, // Rewrites getClass calls on primitive types.
Expand Down
31 changes: 22 additions & 9 deletions compiler/src/dotty/tools/dotc/transform/Constructors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,24 @@ class Constructors extends MiniPhaseTransform with IdentityDenotTransformer { th
import tpd._

override def phaseName: String = "constructors"
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Memoize], classOf[HoistSuperArgs])
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[HoistSuperArgs])
override def runsAfterGroupsOf: Set[Class[_ <: Phase]] = Set(classOf[Memoize])
// Memoized needs to be finished because we depend on the ownerchain after Memoize
// when checking whether an ident is an access in a constructor or outside it.
// This test is done in the right-hand side of a value definition. If Memoize
// was in the same group as Constructors, the test on the rhs ident would be
// performed before the rhs undergoes the owner change. This would lead
// to more symbls being retained as parameters. Test case is
Copy link
Member

Choose a reason for hiding this comment

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

typo: symbls -> symbols

//
// dotc tests/pos/captuing.scala -Xprint:constr
Copy link
Member

Choose a reason for hiding this comment

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

typo: captuing -> capturing

//
// `sf` should not be retained as a filed of class `MT`.

/** The private vals that are known to be retained as class fields */
private val retainedPrivateVals = mutable.Set[Symbol]()

/** The private vals whose definition comes before the current focus */
private val seenPrivateVals = mutable.Set[Symbol]()

// Collect all private parameter accessors and value definitions that need
// to be retained. There are several reasons why a parameter accessor or
Expand All @@ -40,14 +57,10 @@ class Constructors extends MiniPhaseTransform with IdentityDenotTransformer { th
// 3. It is accessed on an object other than `this`
// 4. It is a mutable parameter accessor
// 5. It is has a wildcard initializer `_`
private val retainedPrivateVals = mutable.Set[Symbol]()
private val seenPrivateVals = mutable.Set[Symbol]()

private def markUsedPrivateSymbols(tree: RefTree)(implicit ctx: Context): Unit = {

val sym = tree.symbol
def retain() =
retainedPrivateVals.add(sym)
def retain() = retainedPrivateVals.add(sym)

if (sym.exists && sym.owner.isClass && mightBeDropped(sym)) {
val owner = sym.owner.asClass
Expand All @@ -58,7 +71,8 @@ class Constructors extends MiniPhaseTransform with IdentityDenotTransformer { th
val method = ctx.owner.enclosingMethod
method.isPrimaryConstructor && ctx.owner.enclosingClass == owner
}
if (inConstructor && (sym.is(ParamAccessor) || seenPrivateVals.contains(sym))) {
if (inConstructor &&
(sym.is(ParamAccessor) || seenPrivateVals.contains(sym))) {
// used inside constructor, accessed on this,
// could use constructor argument instead, no need to retain field
}
Expand All @@ -79,8 +93,7 @@ class Constructors extends MiniPhaseTransform with IdentityDenotTransformer { th
}

override def transformValDef(tree: tpd.ValDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
if (mightBeDropped(tree.symbol))
(if (isWildcardStarArg(tree.rhs)) retainedPrivateVals else seenPrivateVals) += tree.symbol
Copy link
Member

Choose a reason for hiding this comment

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

Why was this condition dropped?

Copy link
Contributor Author

@odersky odersky Jul 14, 2017

Choose a reason for hiding this comment

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

It is (probably) dead code. The test looks non-sensical to me. I fail to see how a definition of a class member can end up as something like this:

 val xs = y: _*

Even if it did, why would it make a difference? I put in an assert to flag the condition, but it never triggered in all our tests.

if (mightBeDropped(tree.symbol)) seenPrivateVals += tree.symbol
tree
}

Expand Down
1 change: 1 addition & 0 deletions tests/run/capturing.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
private final java.lang.String MT.s
9 changes: 9 additions & 0 deletions tests/run/capturing.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class MT(sf: MT => String) {
// `s` is retained as a field, but `sf` should not be.
val s = sf(this)
}
object Test extends App {
Copy link
Member

@smarter smarter Jul 14, 2017

Choose a reason for hiding this comment

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

I think we've deprecated/discouraged the use of App

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 I am not sure why? I hate to write all these main methods.

Copy link
Member

Choose a reason for hiding this comment

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

See #559

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am still not sure why we use LegacyApp instead of App now. They seem to be equivalent.

Copy link
Member

Choose a reason for hiding this comment

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

/cc @DarkDimius do you remember why LegacyApp had to be introduced?

def printFields(obj: Any) =
println(obj.getClass.getDeclaredFields.map(_.toString).sorted.deep.mkString("\n"))
printFields(new MT(_ => ""))
}