Skip to content

Commit 0c99a37

Browse files
committed
Take parents of class into account when determining NoInits flags
We declare a class (not a trait) impure if it passes arguments to its parents. This is a very conservative estimate. It's hard to do better, though, since parent expressions are not always typed when we need to decide class purity. So we cannot use `isPureExpr` on argument expressions to find out more.
1 parent 2a0ab6f commit 0c99a37

File tree

4 files changed

+26
-8
lines changed

4 files changed

+26
-8
lines changed

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
241241
}
242242

243243
/** The largest subset of {NoInits, PureInterface} that a
244-
* trait enclosing this statement can have as flags.
244+
* trait or class enclosing this statement can have as flags.
245245
*/
246246
def defKind(tree: Tree)(implicit ctx: Context): FlagSet = unsplice(tree) match {
247247
case EmptyTree | _: Import => NoInitsInterface
@@ -254,6 +254,21 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
254254
case _ => EmptyFlags
255255
}
256256

257+
/** The largest subset of {NoInits, PureInterface} that a
258+
* trait or class with these parents can have as flags.
259+
*/
260+
def parentsKind(parents: List[Tree])(implicit ctx: Context): FlagSet = parents match {
261+
case Nil => NoInitsInterface
262+
case Apply(_, _ :: _) :: _ => EmptyFlags
263+
case _ :: parents1 => parentsKind(parents1)
264+
}
265+
266+
/** The largest subset of {NoInits, PureInterface} that a
267+
* trait or class with this body can have as flags.
268+
*/
269+
def bodyKind(body: List[Tree])(implicit ctx: Context): FlagSet =
270+
(NoInitsInterface /: body)((fs, stat) => fs & defKind(stat))
271+
257272
/** Checks whether predicate `p` is true for all result parts of this expression,
258273
* where we zoom into Ifs, Matches, and Blocks.
259274
*/

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,14 @@ object SymDenotations {
167167
/** Unset given flags(s) of this denotation */
168168
final def resetFlag(flags: FlagSet): Unit = { myFlags &~= flags }
169169

170-
/** Set applicable flags from `flags` which is a subset of {NoInits, PureInterface} */
171-
final def setNoInitsFlags(flags: FlagSet): Unit = {
172-
val mask = if (myFlags.is(Trait)) NoInitsInterface else NoInits
173-
setFlag(flags & mask)
174-
}
170+
/** Set applicable flags in {NoInits, PureInterface}
171+
* @param parentFlags The flags that match the class or trait's parents
172+
* @param bodyFlags The flags that match the class or trait's body
173+
*/
174+
final def setNoInitsFlags(parentFlags: FlagSet, bodyFlags: FlagSet): Unit =
175+
setFlag(
176+
if (myFlags.is(Trait)) NoInitsInterface & bodyFlags // no parents are initialized from a trait
177+
else NoInits & bodyFlags & parentFlags)
175178

176179
private def isCurrent(fs: FlagSet) =
177180
fs <= (

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ class TreeUnpickler(reader: TastyReader,
851851
else EmptyValDef
852852
cls.info = ClassInfo(cls.owner.thisType, cls, parentTypes, cls.unforcedDecls,
853853
if (self.isEmpty) NoType else self.tpt.tpe)
854-
cls.setNoInitsFlags(fork.indexStats(end))
854+
cls.setNoInitsFlags(parentsKind(parents), fork.indexStats(end))
855855
val constr = readIndexedDef().asInstanceOf[DefDef]
856856
val mappedParents = parents.map(_.changeOwner(localDummy, constr.symbol))
857857

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -991,7 +991,7 @@ class Namer { typer: Typer =>
991991
if (isDerivedValueClass(cls)) cls.setFlag(Final)
992992
cls.info = avoidPrivateLeaks(cls, cls.pos)
993993
cls.baseClasses.foreach(_.invalidateBaseTypeCache()) // we might have looked before and found nothing
994-
cls.setNoInitsFlags((NoInitsInterface /: impl.body) ((fs, stat) => fs & untpd.defKind(stat)))
994+
cls.setNoInitsFlags(parentsKind(parents), bodyKind(rest))
995995
if (cls.isNoInitsClass) cls.primaryConstructor.setFlag(Stable)
996996
}
997997
}

0 commit comments

Comments
 (0)