File tree 5 files changed +97
-3
lines changed
compiler/src/dotty/tools/dotc
5 files changed +97
-3
lines changed Original file line number Diff line number Diff line change @@ -101,7 +101,8 @@ class Compiler {
101
101
new LazyVals , // Expand lazy vals
102
102
new Memoize , // Add private fields to getters and setters
103
103
new NonLocalReturns , // Expand non-local returns
104
- new CapturedVars ) :: // Represent vars captured by closures as heap objects
104
+ new CapturedVars , // Represent vars captured by closures as heap objects
105
+ new ElimOuterAccessors ) :: // Drop unused outer accessors
105
106
List (new Constructors , // Collect initialization code in primary constructors
106
107
// Note: constructors changes decls in transformTemplate, no InfoTransformers should be added after it
107
108
new FunctionalInterfaces , // Rewrites closures to implement @specialized types of Functions.
Original file line number Diff line number Diff line change @@ -1079,9 +1079,15 @@ object SymDenotations {
1079
1079
final def lexicallyEnclosingClass (implicit ctx : Context ): Symbol =
1080
1080
if (! exists || isClass) symbol else owner.lexicallyEnclosingClass
1081
1081
1082
+ /** A class is extensible if it is not final, nor a module class,
1083
+ * nor an anonymous class.
1084
+ */
1085
+ final def isExtensibleClass (using Context ): Boolean =
1086
+ isClass && ! isOneOf(FinalOrModuleClass ) && ! isAnonymousClass
1087
+
1082
1088
/** A symbol is effectively final if it cannot be overridden in a subclass */
1083
1089
final def isEffectivelyFinal (implicit ctx : Context ): Boolean =
1084
- isOneOf(EffectivelyFinalFlags ) || ! owner.isClass || owner.isOneOf( FinalOrModuleClass ) || owner.isAnonymousClass
1090
+ isOneOf(EffectivelyFinalFlags ) || ! owner.isExtensibleClass
1085
1091
1086
1092
/** A class is effectively sealed if has the `final` or `sealed` modifier, or it
1087
1093
* is defined in Scala 3 and is neither abstract nor open.
Original file line number Diff line number Diff line change @@ -31,7 +31,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
31
31
32
32
override def phaseName : String = Constructors .name
33
33
override def runsAfter : Set [String ] = Set (HoistSuperArgs .name)
34
- override def runsAfterGroupsOf : Set [String ] = Set (Memoize .name)
34
+ override def runsAfterGroupsOf : Set [String ] = Set (Memoize .name, ElimOuterAccessors .name )
35
35
// Memoized needs to be finished because we depend on the ownerchain after Memoize
36
36
// when checking whether an ident is an access in a constructor or outside it.
37
37
// This test is done in the right-hand side of a value definition. If Memoize
Original file line number Diff line number Diff line change
1
+ package dotty .tools .dotc
2
+ package transform
3
+
4
+ import core ._
5
+ import MegaPhase .MiniPhase
6
+ import dotty .tools .dotc .core .Contexts .Context
7
+ import ast ._
8
+ import Trees ._
9
+ import Flags ._
10
+ import Symbols ._
11
+ import Decorators ._
12
+ import DenotTransformers ._
13
+ import collection .mutable
14
+
15
+ object ElimOuterAccessors :
16
+ val name : String = " elimOuterAccessors"
17
+
18
+ /** Drops outer accessors of final classes that are unused */
19
+ class ElimOuterAccessors extends MiniPhase with IdentityDenotTransformer :
20
+ thisPhase =>
21
+ import tpd ._
22
+
23
+ override def phaseName : String = ElimOuterAccessors .name
24
+
25
+ override def changesMembers : Boolean = true // the phase drops outer accessors
26
+
27
+ private def mightBeDropped (sym : Symbol )(using Context ) =
28
+ sym.is(OuterAccessor ) && ! sym.owner.isExtensibleClass
29
+
30
+ /** The accessed outer accessors that might otherwise be dropped */
31
+ private val retainedAccessors = mutable.Set [Symbol ]()
32
+
33
+ private def markAccessed (tree : RefTree )(implicit ctx : Context ): Tree =
34
+ val sym = tree.symbol
35
+ if mightBeDropped(sym) then retainedAccessors += sym
36
+ tree
37
+
38
+ def transformStat (tree : Tree )(using Context ): Tree =
39
+ val sym = tree.symbol
40
+ if mightBeDropped(sym) && ! retainedAccessors.remove(sym) then
41
+ sym.dropAfter(thisPhase)
42
+ EmptyTree
43
+ else
44
+ tree
45
+
46
+ override def transformIdent (tree : Ident )(using Context ): Tree =
47
+ markAccessed(tree)
48
+
49
+ override def transformSelect (tree : Select )(using Context ): Tree =
50
+ markAccessed(tree)
51
+
52
+ override def transformTemplate (tree : Template )(using Context ): Tree =
53
+ cpy.Template (tree)(body = tree.body.map(transformStat).filter(_ != EmptyTree ))
Original file line number Diff line number Diff line change
1
+ trait Okay extends Serializable {
2
+ def okay : Okay
3
+ }
4
+
5
+ class Foo {
6
+ def okay1 : Okay = new Okay () {
7
+ val okay : Okay = this
8
+ }
9
+ def okay2 : Okay = new Okay {
10
+ val okay : Okay = okay1
11
+ }
12
+ }
13
+
14
+ object Test {
15
+ def main (args : Array [String ]): Unit = {
16
+ val foo = new Foo
17
+ println(roundTrip(foo.okay1))
18
+ println(roundTrip(foo.okay2))
19
+ }
20
+
21
+ def roundTrip [A ](a : A ): A = {
22
+ import java .io ._
23
+
24
+ val aos = new ByteArrayOutputStream ()
25
+ val oos = new ObjectOutputStream (aos)
26
+ oos.writeObject(a)
27
+ oos.close()
28
+ val ais = new ByteArrayInputStream (aos.toByteArray())
29
+ val ois : ObjectInputStream = new ObjectInputStream (ais)
30
+ val newA = ois.readObject()
31
+ ois.close()
32
+ newA.asInstanceOf [A ]
33
+ }
34
+ }
You can’t perform that action at this time.
0 commit comments