Skip to content

Commit ee01c47

Browse files
committed
Adjust purity of trait with lazy member
[Cherry-picked d364992][modified]
1 parent 38c58d0 commit ee01c47

File tree

9 files changed

+71
-17
lines changed

9 files changed

+71
-17
lines changed

‎compiler/src/dotty/tools/dotc/ast/TreeInfo.scala‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,9 @@ trait UntypedTreeInfo extends TreeInfo[Untyped]{self: Trees.Instance[Untyped]
454454
*/
455455
privatedefdefKind(tree: Tree)(usingContext):FlagSet= unsplice(tree) match{
456456
caseEmptyTree|_: Import=>NoInitsInterface
457-
casetree: TypeDef=>if (tree.isClassDef) NoInitselseNoInitsInterface
457+
casetree: TypeDef=>
458+
if tree.isClassDef thenNoInits
459+
elseNoInitsInterface
458460
casetree: DefDef=>
459461
if tree.unforcedRhs ==EmptyTree
460462
&& tree.paramss.forall{
@@ -463,8 +465,6 @@ trait UntypedTreeInfo extends TreeInfo[Untyped]{self: Trees.Instance[Untyped]
463465
}
464466
then
465467
NoInitsInterface
466-
elseif tree.mods.is(Given) && tree.paramss.isEmpty then
467-
EmptyFlags// might become a lazy val: TODO: check whether we need to suppress NoInits once we have new lazy val impl
468468
else
469469
NoInits
470470
casetree: ValDef=>if (tree.unforcedRhs ==EmptyTree) NoInitsInterfaceelseEmptyFlags

‎compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -773,8 +773,8 @@ class TreeUnpickler(reader: TastyReader,
773773
if (sym.isTerm &&!sym.isOneOf(DeferredOrLazyOrMethod))
774774
initsFlags =EmptyFlags
775775
elseif (sym.isClass ||
776-
sym.is(Method, butNot =Deferred) &&!sym.isConstructor)
777-
initsFlags &=NoInits
776+
sym.isOneOf(Lazy|Method, butNot =Deferred) &&!sym.isConstructor)
777+
initsFlags &=NoInits// i.e. initsFlags &~= PureInterface
778778
caseIMPORT|EXPORT=>
779779
skipTree()
780780
casePACKAGE=>

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

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package dotc
33
packagetransform
44

55
importMegaPhase.*
6+
importast.tpd.*
67
importcore.DenotTransformers.*
78
importcore.Symbols.*
89
importcore.Contexts.*
@@ -15,10 +16,8 @@ import core.Names.*
1516
importcore.NameOps.*
1617
importcore.NameKinds.SuperArgName
1718

18-
importdotty.tools.dotc.ast.tpd
19-
20-
importcollection.mutable
2119
importscala.annotation.tailrec
20+
importscala.collection.mutable
2221

2322
/** This phase adds outer accessors to classes and traits that need them.
2423
* Compared to Scala 2.x, it tries to minimize the set of classes
@@ -36,7 +35,6 @@ import scala.annotation.tailrec
3635
*/
3736
classExplicitOuterextendsMiniPhasewithInfoTransformer{thisPhase =>
3837
importExplicitOuter.*
39-
importast.tpd.*
4038

4139
overridedefphaseName:String=ExplicitOuter.name
4240

@@ -64,7 +62,7 @@ class ExplicitOuter extends MiniPhase with InfoTransformer{thisPhase =>
6462
* Furthermore, if a parent trait might have an outer accessor,
6563
* provide an implementation for the outer accessor by computing the parent's
6664
* outer from the parent type prefix. If the trait ends up not having an outer accessor
67-
* after all, the implementation is redundant, but does not harm.
65+
* after all, the implementation is redundant, but does no harm.
6866
* The same logic is not done for non-trait parent classes because for them the outer
6967
* pointer is passed in the super constructor, which will be implemented later in
7068
* a separate phase which needs to run after erasure. However, we make sure here
@@ -111,7 +109,7 @@ class ExplicitOuter extends MiniPhase with InfoTransformer{thisPhase =>
111109
else impl
112110
}
113111

114-
overridedeftransformClosure(tree: Closure)(usingContext):tpd.Tree={
112+
overridedeftransformClosure(tree: Closure)(usingContext):Tree={
115113
if (tree.tpt ne EmptyTree){
116114
valcls= tree.tpt.asInstanceOf[TypeTree].tpe.classSymbol
117115
if (cls.exists && hasOuter(cls.asClass))
@@ -122,7 +120,6 @@ class ExplicitOuter extends MiniPhase with InfoTransformer{thisPhase =>
122120
}
123121

124122
objectExplicitOuter{
125-
importast.tpd.*
126123

127124
valname:String="explicitOuter"
128125
valdescription:String="add accessors to outer classes from nested ones"
@@ -217,11 +214,12 @@ object ExplicitOuter{
217214
* - we need to potentially pass along outer to a parent class or trait
218215
*/
219216
privatedefneedsOuterAlways(cls: ClassSymbol)(usingContext):Boolean=
220-
needsOuterIfReferenced(cls) &&
221-
(!hasOnlyLocalInstantiation(cls) ||// needs outer because we might not know whether outer is referenced or not
222-
cls.mixins.exists(needsOuterIfReferenced) ||// needs outer for parent traits
223-
cls.info.parents.exists(parent =>// needs outer to potentially pass along to parent
224-
needsOuterIfReferenced(parent.classSymbol.asClass)))
217+
needsOuterIfReferenced(cls)
218+
&& (!hasOnlyLocalInstantiation(cls) // needs outer because we might not know whether outer is referenced or not
219+
|| cls.mixins.exists(needsOuterIfReferenced) // needs outer for parent traits
220+
|| cls.info.parents.exists: parent =>// needs outer to potentially pass along to parent
221+
needsOuterIfReferenced(parent.classSymbol.asClass)
222+
)
225223

226224
/** Class is only instantiated in the compilation unit where it is defined */
227225
privatedefhasOnlyLocalInstantiation(cls: ClassSymbol)(usingContext):Boolean=

‎tests/run/i23245a/api.scala‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
packagelogadapter:
3+
4+
traitAbstractLogAdapter:
5+
definfo(message: String):Unit
6+
7+
traitAbstractApi[T<:AbstractLogAdapter]:
8+
deflogAdapterFor(loggerName: String):T
9+
traitSelfLogging:
10+
givenadapter:T= logAdapterFor(this.getClass.getName)
11+
// workaround:
12+
//given () => T = logAdapterFor(this.getClass.getName)
13+
// or
14+
//private val adapter = logAdapterFor(this.getClass.getName)
15+
//given T = adapter
16+
// or just pollute the interface so it's never taken as pure
17+
//private val z = 42
18+
19+
objectApiextendsAbstractApi[LogAdapter]:
20+
deflogAdapterFor(loggerName: String):LogAdapter=newLogAdapter(loggerName)
21+
22+
classLogAdapter(loggerName: String) extendsAbstractLogAdapter:
23+
definfo(message: String):Unit=System.err.println(s"INFO [${loggerName}] ${message}")

‎tests/run/i23245a/test_2.scala‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
3+
objectTestextends logadapter.Api.SelfLogging:
4+
defmain(args: Array[String]):Unit=
5+
summon[logadapter.LogAdapter].info("Hello")
6+

‎tests/run/i23245b/outer.scala‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
traitT:
3+
deff=42
4+
traitD:
5+
lazyvalg= f
6+
7+
objectCextendsT
8+
9+
// D parent of Z is taken as PureInterface under separate compilation
10+
// and thus doesn't get an outer.

‎tests/run/i23245b/test_2.scala‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
objectZextendsC.D
3+
4+
@main defTest=println:
5+
Z.g

‎tests/run/i23245c/outer.scala‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
traitT:
3+
deff=42
4+
traitD:
5+
lazyvalg= f
6+
7+
objectCextendsT

‎tests/run/i23245c/test.scala‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
objectZextendsC.D
3+
4+
@main defTest=println:
5+
Z.g

0 commit comments

Comments
(0)