From 7e66e65d754fd2b9a7cd5bb245d4d3d590dce45a Mon Sep 17 00:00:00 2001 From: Anatolii Date: Thu, 24 Oct 2019 15:08:42 +0200 Subject: [PATCH 01/20] Drop the workaround -Yno-inline flag from semanticdb --- community-build/community-projects/semanticdb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/community-build/community-projects/semanticdb b/community-build/community-projects/semanticdb index 17f4c738e73e..05b8001beade 160000 --- a/community-build/community-projects/semanticdb +++ b/community-build/community-projects/semanticdb @@ -1 +1 @@ -Subproject commit 17f4c738e73ea5d3ec86c00aa53ab3142dc0e77e +Subproject commit 05b8001beade3492f7eb8ab9425dd7454f66fe4b From 5e7ba22ceebfaaede4981c6a298006286eb8dfed Mon Sep 17 00:00:00 2001 From: Anatolii Date: Tue, 15 Oct 2019 15:02:01 +0200 Subject: [PATCH 02/20] Check flags that are not supposed to be mutated by completion --- compiler/src/dotty/tools/dotc/core/Flags.scala | 1 - .../dotty/tools/dotc/core/SymDenotations.scala | 15 ++++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 8161b6d11a6a..d3d66dfee8e0 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -434,7 +434,6 @@ object Flags { commonFlags(Module, Param, Synthetic, Package, Local, Mutable, Trait) /** Flags that are not (re)set when completing the denotation - * TODO: Should check that FromStartFlags do not change in completion */ val FromStartFlags: FlagSet = commonFlags( Module, Package, Deferred, Method, Case, diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 65aa4dc58d0d..9be6ba8a8f5d 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -160,6 +160,11 @@ object SymDenotations { */ private[dotc] final def flagsUNSAFE: FlagSet = myFlags + inline private def setMyFlags(flags: FlagSet) = + if isCompleting then assert((flags & FromStartFlags).isEmpty, + s"Illegal mutation of flags ${flags & FromStartFlags} on completion of $this") + myFlags = flags + final def flagsString(implicit ctx: Context): String = flags.flagsString /** Adapt flag set to this denotation's term or type nature */ @@ -167,13 +172,13 @@ object SymDenotations { /** Update the flag set */ final def flags_=(flags: FlagSet): Unit = - myFlags = adaptFlags(flags) + setMyFlags(adaptFlags(flags)) /** Set given flags(s) of this denotation */ - final def setFlag(flags: FlagSet): Unit = { myFlags |= flags } + final def setFlag(flags: FlagSet): Unit = { setMyFlags(myFlags | flags) } /** Unset given flags(s) of this denotation */ - final def resetFlag(flags: FlagSet): Unit = { myFlags &~= flags } + final def resetFlag(flags: FlagSet): Unit = { setMyFlags(myFlags &~ flags) } /** Set applicable flags in {NoInits, PureInterface} * @param parentFlags The flags that match the class or trait's parents @@ -237,7 +242,7 @@ object SymDenotations { indent += 1 if (myFlags.is(Touched)) throw CyclicReference(this) - myFlags |= Touched + setMyFlags(myFlags | Touched) // completions.println(s"completing ${this.debugString}") try completer.complete(this)(ctx.withPhase(validFor.firstPhaseId)) @@ -253,7 +258,7 @@ object SymDenotations { } else { if (myFlags.is(Touched)) throw CyclicReference(this) - myFlags |= Touched + setMyFlags(myFlags | Touched) completer.complete(this)(ctx.withPhase(validFor.firstPhaseId)) } From 6a69358525c08359fb6d0cf0568e3192410283d9 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Tue, 15 Oct 2019 15:06:41 +0200 Subject: [PATCH 03/20] Better error message --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 9be6ba8a8f5d..f125955beb71 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -162,7 +162,7 @@ object SymDenotations { inline private def setMyFlags(flags: FlagSet) = if isCompleting then assert((flags & FromStartFlags).isEmpty, - s"Illegal mutation of flags ${flags & FromStartFlags} on completion of $this") + s"Illegal mutation of flags ${(flags & FromStartFlags).flagsString} on completion of $this") myFlags = flags final def flagsString(implicit ctx: Context): String = flags.flagsString From 163c83e636a8caf095c5695ed9c22d720149d272 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Wed, 16 Oct 2019 16:28:04 +0200 Subject: [PATCH 04/20] Flag mutation check case added for loaded classes --- compiler/src/dotty/tools/dotc/config/Config.scala | 2 +- .../src/dotty/tools/dotc/core/SymDenotations.scala | 14 ++++++++++++-- .../src/dotty/tools/dotc/core/SymbolLoaders.scala | 2 ++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 437db786e3a3..8bd7e900f251 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -164,7 +164,7 @@ object Config { final val silentTemplateIndent = true /** If set, prints a trace of all symbol completions */ - final val showCompletions = false + final val showCompletions = true /** If set, enables tracing */ final val tracingEnabled = false diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index f125955beb71..7327a9cab601 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -149,6 +149,14 @@ object SymDenotations { private var myPrivateWithin: Symbol = initPrivateWithin private var myAnnotations: List[Annotation] = Nil + private[this] var isLoading = false + private[this] var wasLoaded = false + + def startedLoading() = isLoading = true + def finishedLoading() = + isLoading = false + wasLoaded = true + /** The owner of the symbol; overridden in NoDenotation */ def owner: Symbol = maybeOwner @@ -161,8 +169,10 @@ object SymDenotations { private[dotc] final def flagsUNSAFE: FlagSet = myFlags inline private def setMyFlags(flags: FlagSet) = - if isCompleting then assert((flags & FromStartFlags).isEmpty, - s"Illegal mutation of flags ${(flags & FromStartFlags).flagsString} on completion of $this") + lazy val immutableFlags = if wasLoaded then AfterLoadFlags else FromStartFlags + lazy val changedImmutableFlags = (myFlags ^ flags) & immutableFlags + if isCompleting && !isLoading then assert(changedImmutableFlags.isEmpty, + s"Illegal mutation of flags ${changedImmutableFlags.flagsString} on completion of $this") myFlags = flags final def flagsString(implicit ctx: Context): String = flags.flagsString diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 5fc455f1d868..43eb24228aba 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -394,6 +394,7 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader { load(root) def load(root: SymDenotation)(implicit ctx: Context): Unit = { + root.startedLoading() val (classRoot, moduleRoot) = rootDenots(root.asClass) val classfileParser = new ClassfileParser(classfile, classRoot, moduleRoot)(ctx) val result = classfileParser.run() @@ -404,6 +405,7 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader { moduleRoot.classSymbol.rootTreeOrProvider = unpickler case _ => } + root.finishedLoading() } private def mayLoadTreesFromTasty(implicit ctx: Context): Boolean = From d8e10850f33794168d2650af0fad577a215233c1 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Wed, 16 Oct 2019 17:15:16 +0200 Subject: [PATCH 05/20] Fix loading of the module classes --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 6 ++++-- .../src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 7327a9cab601..f7aa817f3813 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -152,7 +152,9 @@ object SymDenotations { private[this] var isLoading = false private[this] var wasLoaded = false - def startedLoading() = isLoading = true + def startedLoading() = + isLoading = true + def finishedLoading() = isLoading = false wasLoaded = true @@ -168,7 +170,7 @@ object SymDenotations { */ private[dotc] final def flagsUNSAFE: FlagSet = myFlags - inline private def setMyFlags(flags: FlagSet) = + private def setMyFlags(flags: FlagSet) = lazy val immutableFlags = if wasLoaded then AfterLoadFlags else FromStartFlags lazy val changedImmutableFlags = (myFlags ^ flags) & immutableFlags if isCompleting && !isLoading then assert(changedImmutableFlags.isEmpty, diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index c8391e959cad..2be6a36203cb 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -541,6 +541,7 @@ class TreeUnpickler(reader: TastyReader, val sym = roots.find(root => (root.owner eq ctx.owner) && root.name == name) match { case Some(rootd) => + rootd.startedLoading() pickling.println(i"overwriting ${rootd.symbol} # ${rootd.hashCode}") rootd.symbol.coord = coord rootd.info = adjustIfModule( @@ -548,6 +549,7 @@ class TreeUnpickler(reader: TastyReader, rootd.flags = flags &~ Touched // allow one more completion rootd.setPrivateWithin(privateWithin) seenRoots += rootd.symbol + rootd.finishedLoading() rootd.symbol case _ => val completer = adjustIfModule(new Completer(subReader(start, end))) From 54cedb741ef21c07bab83bd439030ec9448035b7 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Wed, 16 Oct 2019 18:04:33 +0200 Subject: [PATCH 06/20] Fix neg completeFromSource test Late compilation counts as loading --- compiler/src/dotty/tools/dotc/config/Config.scala | 2 +- compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 8bd7e900f251..437db786e3a3 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -164,7 +164,7 @@ object Config { final val silentTemplateIndent = true /** If set, prints a trace of all symbol completions */ - final val showCompletions = true + final val showCompletions = false /** If set, enables tracing */ final val tracingEnabled = false diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 43eb24228aba..57cce2e48fbd 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -416,7 +416,9 @@ class SourcefileLoader(val srcfile: AbstractFile) extends SymbolLoader { def description(implicit ctx: Context): String = "source file " + srcfile.toString override def sourceFileOrNull: AbstractFile = srcfile def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = + root.startedLoading() ctx.run.lateCompile(srcfile, typeCheck = ctx.settings.YretainTrees.value) + root.finishedLoading() } /** A NoCompleter which is also a SymbolLoader. */ From c1de67968008da6f196e47e45281c72725e81487 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Thu, 17 Oct 2019 11:17:01 +0200 Subject: [PATCH 07/20] Mark Scala2Unpickler-processed denotations as loading So that we can modify their flags. --- .../tools/dotc/core/unpickleScala2/Scala2Unpickler.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 4bfcd1b5236d..b484520aa463 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -143,8 +143,8 @@ object Scala2Unpickler { /** Unpickle symbol table information descending from a class and/or module root * from an array of bytes. * @param bytes bytearray from which we unpickle - * @param classroot the top-level class which is unpickled, or NoSymbol if inapplicable - * @param moduleroot the top-level module class which is unpickled, or NoSymbol if inapplicable + * @param classRoot the top-level class which is unpickled, or NoSymbol if inapplicable + * @param moduleClassRoot the top-level module class which is unpickled, or NoSymbol if inapplicable * @param filename filename associated with bytearray, only used for error messages */ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: ClassDenotation)(ictx: Context) @@ -191,6 +191,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas def run()(implicit ctx: Context): Unit = try { + classRoot.startedLoading() + moduleRoot.startedLoading() var i = 0 while (i < index.length) { if (entries(i) == null && isSymbolEntry(i)) { @@ -225,6 +227,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas } i += 1 } + classRoot.finishedLoading() + moduleRoot.finishedLoading() } catch { case ex: RuntimeException => handleRuntimeException(ex) From 4d46b599c933d56be192958d60e63aef460e308a Mon Sep 17 00:00:00 2001 From: Anatolii Date: Fri, 18 Oct 2019 11:18:43 +0200 Subject: [PATCH 08/20] Do not reset the GivenOrImplicit flags on implicits without explicit types Also fix a neg test for i3067. After this modification to the completion algorithm, implicit definitions without explicit types stay visible in the implicit scope and hence, the error of the missing implicit is not reporter. This is fine, however, since the real error to be fixed is the lack of an explicit type of the implicit value, not the lack of the implicit value itself. --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 4 +--- tests/neg/i3067.scala | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index e185ce523e5f..0180f24af94c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -762,10 +762,8 @@ class Namer { typer: Typer => else bound } - def missingType(sym: Symbol, modifier: String)(implicit ctx: Context): Unit = { + def missingType(sym: Symbol, modifier: String)(implicit ctx: Context): Unit = ctx.error(s"${modifier}type of implicit definition needs to be given explicitly", sym.sourcePos) - sym.resetFlag(GivenOrImplicit) - } /** The completer of a symbol defined by a member def or import (except ClassSymbols) */ class Completer(val original: Tree)(implicit ctx: Context) extends LazyType with SymbolLoaders.SecondCompleter { diff --git a/tests/neg/i3067.scala b/tests/neg/i3067.scala index d7822c91a9f0..4bee02a4ad1c 100644 --- a/tests/neg/i3067.scala +++ b/tests/neg/i3067.scala @@ -10,6 +10,6 @@ object o { implicit def y = "abc" // error - implicit object a extends Test(_ map identity) // error // error: no implicit argument found + implicit object a extends Test(_ map identity) // error implicit object b extends Test(_ map identity) // error // error: cyclic reference } From e99d073293ca5361fe2a986dbb877f294c882fee Mon Sep 17 00:00:00 2001 From: Anatolii Date: Fri, 18 Oct 2019 13:29:43 +0200 Subject: [PATCH 09/20] Drop `forceInline` annotation It was needed to make Dotty cross-compile to Scala 2 before full bootstrap. Its direct semantics is about adding the `inline` flag to a symbol annotated by it. `inline` flag, however, is listed as one of the flags that are not supposed to be modified by completion of symbols. Hence, having `forceInline` annotation is in violation of our own assumptions about completion. Before full bootstrap, we were not able to drop this annotation, however, now that we have the full bootstrap, we can do it. --- .../tools/dotc/core/ConstraintHandling.scala | 2 +- .../src/dotty/tools/dotc/core/Definitions.scala | 1 - .../dotty/tools/dotc/core/SymDenotations.scala | 11 ++--------- .../src/dotty/tools/dotc/core/Symbols.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- .../tools/dotc/parsing/xml/MarkupParsers.scala | 2 +- .../src/dotty/tools/dotc/typer/ConstFold.scala | 2 +- .../src/dotty/tools/dotc/typer/Inliner.scala | 5 +---- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 -- .../tools/dotc/typer/QuotesAndSplices.scala | 2 +- compiler/src/dotty/tools/dotc/util/Stats.scala | 6 ++---- .../tools/backend/jvm/InlineBytecodeTests.scala | 2 +- library/src/dotty/DottyPredef.scala | 8 ++++---- library/src/scala/forceInline.scala | 17 ----------------- library/src/scala/internal/Chars.scala | 2 +- 15 files changed, 17 insertions(+), 49 deletions(-) delete mode 100644 library/src/scala/forceInline.scala diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index c2800bb7dc58..e8c9c91cc144 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -205,7 +205,7 @@ trait ConstraintHandling[AbstractContext] { else isSubType(tp1, tp2) - @forceInline final def inFrozenConstraint[T](op: => T): T = { + inline final def inFrozenConstraint[T](op: => T): T = { val savedFrozen = frozenConstraint val savedLambda = caseLambda frozenConstraint = true diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 29ede1a187c2..f9ad5bd52925 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -750,7 +750,6 @@ class Definitions { @tu lazy val DeprecatedAnnot: ClassSymbol = ctx.requiredClass("scala.deprecated") @tu lazy val ImplicitAmbiguousAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.implicitAmbiguous") @tu lazy val ImplicitNotFoundAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.implicitNotFound") - @tu lazy val ForceInlineAnnot: ClassSymbol = ctx.requiredClass("scala.forceInline") @tu lazy val InlineParamAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.InlineParam") @tu lazy val InvariantBetweenAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.InvariantBetween") @tu lazy val MainAnnot: ClassSymbol = ctx.requiredClass("scala.main") diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index f7aa817f3813..00052529dcda 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -935,17 +935,10 @@ object SymDenotations { /** Is this a Scala 2 macro */ final def isScala2Macro(implicit ctx: Context): Boolean = is(Macro) && symbol.owner.is(Scala2x) - /** An erased value or an inline method, excluding @forceInline annotated methods. - * The latter have to be kept around to get to parity with Scala. - * This is necessary at least until we have full bootstrap. Right now - * dotty-bootstrapped involves running the Dotty compiler compiled with Scala 2 with - * a Dotty runtime library compiled with Dotty. If we erase @forceInline annotated - * methods, this means that the support methods in dotty.runtime.LazyVals vanish. - * But they are needed for running the lazy val implementations in the Scala-2 compiled compiler. + /** An erased value or an inline method. */ def isEffectivelyErased(implicit ctx: Context): Boolean = - is(Erased) || - isInlineMethod && unforcedAnnotation(defn.ForceInlineAnnot).isEmpty + is(Erased) || isInlineMethod /** ()T and => T types should be treated as equivalent for this symbol. * Note: For the moment, we treat Scala-2 compiled symbols as loose matching, diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index f70288313aa8..3ee8751a1f19 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -908,6 +908,6 @@ object Symbols { override def toString: String = value.asScala.toString() } - @forceInline def newMutableSymbolMap[T]: MutableSymbolMap[T] = + inline def newMutableSymbolMap[T]: MutableSymbolMap[T] = new MutableSymbolMap(new java.util.IdentityHashMap[Symbol, T]()) } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 561a291ae188..3817eb24949c 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4432,7 +4432,7 @@ object Types { abstract class VariantTraversal { protected[core] var variance: Int = 1 - @forceInline protected def atVariance[T](v: Int)(op: => T): T = { + inline protected def atVariance[T](v: Int)(op: => T): T = { val saved = variance variance = v val res = op diff --git a/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala b/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala index 82a059b848c9..cef9cb488a4e 100644 --- a/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala @@ -317,7 +317,7 @@ object MarkupParsers { } /** Some try/catch/finally logic used by xLiteral and xLiteralPattern. */ - @forceInline private def xLiteralCommon(f: () => Tree, ifTruncated: String => Unit): Tree = { + inline private def xLiteralCommon(f: () => Tree, ifTruncated: String => Unit): Tree = { assert(parser.in.token == Tokens.XMLSTART) val saved = parser.in.newTokenData saved.copyFrom(parser.in) diff --git a/compiler/src/dotty/tools/dotc/typer/ConstFold.scala b/compiler/src/dotty/tools/dotc/typer/ConstFold.scala index 00abab45a3eb..9b4eef28369a 100644 --- a/compiler/src/dotty/tools/dotc/typer/ConstFold.scala +++ b/compiler/src/dotty/tools/dotc/typer/ConstFold.scala @@ -48,7 +48,7 @@ object ConstFold { } } - @forceInline private def finish[T <: Tree](tree: T)(compX: => Constant)(implicit ctx: Context): T = + inline private def finish[T <: Tree](tree: T)(compX: => Constant)(implicit ctx: Context): T = try { val x = compX if (x ne null) tree.withType(ConstantType(x)).asInstanceOf[T] diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 70f6718de2da..aecdac58e0bb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -33,15 +33,12 @@ import dotty.tools.dotc.transform.{Splicer, TreeMapWithStages} object Inliner { import tpd._ - /** `sym` is an inline method with a known body to inline (note: definitions coming - * from Scala2x class files might be `@forceInline`, but still lack that body). + /** `sym` is an inline method with a known body to inline. */ def hasBodyToInline(sym: SymDenotation)(implicit ctx: Context): Boolean = sym.isInlineMethod && sym.hasAnnotation(defn.BodyAnnot) /** The body to inline for method `sym`, or `EmptyTree` if none exists. - * Note: definitions coming from Scala2x class files might be `@forceInline`, - * but still lack that body. * @pre hasBodyToInline(sym) */ def bodyToInline(sym: SymDenotation)(implicit ctx: Context): Tree = diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 0180f24af94c..78ae95d68afb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -823,8 +823,6 @@ class Namer { typer: Typer => else { val ann = Annotation.deferred(cls)(typedAnnotation(annotTree)) sym.addAnnotation(ann) - if (cls == defn.ForceInlineAnnot && sym.is(Method, butNot = Accessor)) - sym.setFlag(Inline) } } case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala index f38cb69b3c7a..0685a8b7d488 100644 --- a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala +++ b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala @@ -165,7 +165,7 @@ trait QuotesAndSplices { object splitter extends tpd.TreeMap { private var variance: Int = 1 - @forceInline private def atVariance[T](v: Int)(op: => T): T = { + inline private def atVariance[T](v: Int)(op: => T): T = { val saved = variance variance = v val res = op diff --git a/compiler/src/dotty/tools/dotc/util/Stats.scala b/compiler/src/dotty/tools/dotc/util/Stats.scala index acbba5f7b90e..e7a28861fdd4 100644 --- a/compiler/src/dotty/tools/dotc/util/Stats.scala +++ b/compiler/src/dotty/tools/dotc/util/Stats.scala @@ -19,8 +19,7 @@ import collection.mutable override def default(key: String): Int = 0 } - @forceInline - def record(fn: => String, n: => Int = 1): Unit = + inline def record(fn: => String, n: => Int = 1): Unit = if (enabled) doRecord(fn, n) def doRecord(fn: String, n: Int) = @@ -29,8 +28,7 @@ import collection.mutable hits(name) += n } - @forceInline - def trackTime[T](fn: String)(op: => T): T = + inline def trackTime[T](fn: String)(op: => T): T = if (enabled) doTrackTime(fn)(op) else op def doTrackTime[T](fn: String)(op: => T): T = { diff --git a/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala b/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala index 6b206baacdab..78282717be8b 100644 --- a/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala +++ b/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala @@ -13,7 +13,7 @@ class InlineBytecodeTests extends DottyBytecodeTest { val source = """ |class Foo { | inline def foo: Int = 1 - | @forceInline def bar: Int = 1 + | inline def bar: Int = 1 | | def meth1: Unit = foo | def meth2: Unit = bar diff --git a/library/src/dotty/DottyPredef.scala b/library/src/dotty/DottyPredef.scala index 18b16a0283e6..529266cb3922 100644 --- a/library/src/dotty/DottyPredef.scala +++ b/library/src/dotty/DottyPredef.scala @@ -3,12 +3,12 @@ package dotty object DottyPredef { import compiletime.summonFrom - @forceInline final def assert(assertion: => Boolean, message: => Any): Unit = { + inline final def assert(assertion: => Boolean, message: => Any): Unit = { if (!assertion) assertFail(message) } - @forceInline final def assert(assertion: => Boolean): Unit = { + inline final def assert(assertion: => Boolean): Unit = { if (!assertion) assertFail() } @@ -16,9 +16,9 @@ object DottyPredef { def assertFail(): Unit = throw new java.lang.AssertionError("assertion failed") def assertFail(message: => Any): Unit = throw new java.lang.AssertionError("assertion failed: " + message) - @forceInline final def implicitly[T](implicit ev: T): T = ev + inline final def implicitly[T](implicit ev: T): T = ev - @forceInline def locally[T](body: => T): T = body + inline def locally[T](body: => T): T = body /** * Retrieve the single value of a type with a unique inhabitant. diff --git a/library/src/scala/forceInline.scala b/library/src/scala/forceInline.scala deleted file mode 100644 index b08f18fa4542..000000000000 --- a/library/src/scala/forceInline.scala +++ /dev/null @@ -1,17 +0,0 @@ -package scala - -/** An annotation on methods that is equivalent to Dotty `inline` modifier, - * except that it does not imply `erased`. - * - * The annotation should be used instead of the `inline` modifier in code - * that needs to cross compile between Scala 2 and Dotty. - * - * Note that Scala 2 ignores the `@forceInLine` annotation, and one must use - * both the `@inline` and `@forceInline` annotation to inline across the - * two compilers. E.g. - * - * ```scala - * @inline @forceInline def foo = ... - * ``` - */ -class forceInline extends scala.annotation.StaticAnnotation diff --git a/library/src/scala/internal/Chars.scala b/library/src/scala/internal/Chars.scala index 4c0ffeb24fa7..7faaa700007a 100644 --- a/library/src/scala/internal/Chars.scala +++ b/library/src/scala/internal/Chars.scala @@ -33,7 +33,7 @@ object Chars { /** Convert a character to a backslash-u escape */ def char2uescape(c: Char): String = { - @forceInline def hexChar(ch: Int): Char = + inline def hexChar(ch: Int): Char = (( if (ch < 10) '0' else 'A' - 10 ) + ch).toChar char2uescapeArray(2) = hexChar((c >> 12) ) From f098055043f452a89290b93b03ebfba25a1b65d2 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Fri, 18 Oct 2019 13:47:17 +0200 Subject: [PATCH 10/20] Count symbol redefinition on late compilation as symbol loading For the purposes of the capability of flag mutation on completion. --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 78ae95d68afb..88767822ccac 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -337,9 +337,11 @@ class Namer { typer: Typer => val sym = if (prev.exists) { + prev.startedLoading() prev.flags = flags1 prev.info = infoFn(prev.asInstanceOf[S]) prev.setPrivateWithin(privateWithin) + prev.finishedLoading() prev } else symFn(flags1, infoFn, privateWithin) From 46bab0c6b67875393cbb176bb2236987c0fcec0f Mon Sep 17 00:00:00 2001 From: Anatolii Date: Fri, 18 Oct 2019 15:06:46 +0200 Subject: [PATCH 11/20] Remove Macro from FromStartFlags This flag is set on symbol completion based on other semantic info. --- compiler/src/dotty/tools/dotc/core/Flags.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index d3d66dfee8e0..021031cd51bc 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -441,7 +441,7 @@ object Flags { Scala2ExistentialCommon, Mutable, Opaque, Touched, JavaStatic, OuterOrCovariant, LabelOrContravariant, CaseAccessor, Extension, NonMember, Implicit, Given, Permanent, Synthetic, - SuperAccessorOrScala2x, Inline, Macro) + SuperAccessorOrScala2x, Inline) /** Flags that are not (re)set when completing the denotation, or, if symbol is * a top-level class or object, when completing the denotation once the class From d63524067775a099a851053b395082bd734193a6 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Fri, 18 Oct 2019 16:30:13 +0200 Subject: [PATCH 12/20] Fix i7407 test error message FTTB it is a cyclic error. It requests the user to fully specify the type of the method. Once they do so, an intended "implicit not found" message appears. Displaying the correct message directly requires adding `Macro` flag to `FromStartFlags`, which is not correct. Until we find a workaround, this solution is a reasonable trade-off because it offers an unambiguous action (to fully specify the type of the method) for the user to take to see the correct error message. The reason the cyclic error appears in first place is as follows. Given `inline def g = qc`, we typecheck `qc`. However, `qc` requires an implicit QuoteContext which can only be synthetically generated for the bodies of macros. Hence we need to see if `g` is a macro, and to do so, we need to complete it. To complete it, we need to typecheck its body, which yields the cyclic error. --- tests/neg/i7407.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/neg/i7407.scala b/tests/neg/i7407.scala index 03823eb22e68..178692ab9568 100644 --- a/tests/neg/i7407.scala +++ b/tests/neg/i7407.scala @@ -1,2 +1,2 @@ def qc(given ctx: scala.quoted.QuoteContext) = println(ctx) -inline def g = qc // error: no implicit argument +inline def g = qc // error: cyclic reference From a11d99513b62e88bb75052453e3317df89509f5e Mon Sep 17 00:00:00 2001 From: Anatolii Date: Mon, 21 Oct 2019 16:52:47 +0200 Subject: [PATCH 13/20] Tighten flag checking rules on completion Count a denotation as completing if it has the `Touched` flag set. This assumption follows from the definition of the flag `Touched` provided in its javadoc comment in Flags.scala. Also, this commit unconditionally unsets this flag for all denotations once they are completed. The rationale is, again, to comply with the definition of `Touched`. --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 00052529dcda..d45ce7027ce6 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -173,7 +173,7 @@ object SymDenotations { private def setMyFlags(flags: FlagSet) = lazy val immutableFlags = if wasLoaded then AfterLoadFlags else FromStartFlags lazy val changedImmutableFlags = (myFlags ^ flags) & immutableFlags - if isCompleting && !isLoading then assert(changedImmutableFlags.isEmpty, + if myFlags.is(Touched) && !isLoading then assert(changedImmutableFlags.isEmpty, s"Illegal mutation of flags ${changedImmutableFlags.flagsString} on completion of $this") myFlags = flags @@ -254,7 +254,7 @@ object SymDenotations { indent += 1 if (myFlags.is(Touched)) throw CyclicReference(this) - setMyFlags(myFlags | Touched) + myFlags |= Touched // completions.println(s"completing ${this.debugString}") try completer.complete(this)(ctx.withPhase(validFor.firstPhaseId)) @@ -270,9 +270,10 @@ object SymDenotations { } else { if (myFlags.is(Touched)) throw CyclicReference(this) - setMyFlags(myFlags | Touched) + myFlags |= Touched completer.complete(this)(ctx.withPhase(validFor.firstPhaseId)) } + myFlags &~= Touched protected[dotc] def info_=(tp: Type): Unit = { /* // DEBUG From 87217dbac84618cbda0523456f434f8ef2bad732 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Wed, 23 Oct 2019 16:18:50 +0200 Subject: [PATCH 14/20] Introduce conditionally mutable flags wrt completion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some flags do not fall under the definition of the flags that are not mutated during completion. However, in practice, they are almost never mutated on completion and such an event is easy to predict. An example of such a flag is `deferred` which is set only when compiling opaque types – this is part of what makes opaque types work. It is reasonable, hence, to make sure denotations are counted as current even though they have some of such flags if when querying these flags we can predict that they will not change during completion. --- compiler/src/dotty/tools/dotc/core/Flags.scala | 17 ++++++++++++++++- .../dotty/tools/dotc/core/SymDenotations.scala | 15 ++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 021031cd51bc..137ab0e530f4 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -436,7 +436,7 @@ object Flags { /** Flags that are not (re)set when completing the denotation */ val FromStartFlags: FlagSet = commonFlags( - Module, Package, Deferred, Method, Case, + Module, Package, Method, Case, HigherKinded, Param, ParamAccessor, Scala2ExistentialCommon, Mutable, Opaque, Touched, JavaStatic, OuterOrCovariant, LabelOrContravariant, CaseAccessor, @@ -451,6 +451,21 @@ object Flags { val AfterLoadFlags: FlagSet = commonFlags( FromStartFlags, AccessFlags, Final, AccessorOrSealed, LazyOrTrait, SelfName, JavaDefined) + /** Flags that are not mutated during completion when a certain + * condition is satisfied + */ + object ConditionallyImmutableFlags { + val flagsAndConditions: List[(Flag, (given Contexts.Context) => SymDenotations.SymDenotation => Boolean)] = List( + Deferred -> { denot => + denot.is(Opaque) && denot.isType && + !denot.infoOrCompleter.isInstanceOf[SymbolLoader] // If it is loaded, we assume the opaque mechanism has already set the flags correctly + } + ) + + val flags: FlagSet = flagsAndConditions.map(_._1) + .foldLeft(EmptyFlags) { (accum, next) => accum | next } + } + /** A value that's unstable unless complemented with a Stable flag */ val UnstableValueFlags: FlagSet = Mutable | Method diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index d45ce7027ce6..5db2be9b9156 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -201,10 +201,19 @@ object SymDenotations { if (myFlags.is(Trait)) NoInitsInterface & bodyFlags // no parents are initialized from a trait else NoInits & bodyFlags & parentFlags) - private def isCurrent(fs: FlagSet) = - fs <= ( + private def isCurrent(fs: FlagSet)(implicit ctx: Context): Boolean = + val immutableFlags = if (myInfo.isInstanceOf[SymbolLoader]) FromStartFlags - else AfterLoadFlags) + else AfterLoadFlags + val mutableFlagsBeingQueried = fs &~ immutableFlags + + mutableFlagsBeingQueried.isEmpty || ( // All flags are immutable wrt completion + mutableFlagsBeingQueried <= ConditionallyImmutableFlags.flags && // All the mutable flags being queried are not mutated during completion under certain conditions + ConditionallyImmutableFlags.flagsAndConditions.forall { case (flag, condition) => + (flag & mutableFlagsBeingQueried).isEmpty || !condition(this) + } + ) + final def relevantFlagsFor(fs: FlagSet)(implicit ctx: Context) = if (isCurrent(fs)) myFlags else flags From bd4719e10f804e97756211ea4f2d238d9a6fa51b Mon Sep 17 00:00:00 2001 From: Anatolii Date: Wed, 23 Oct 2019 16:32:32 +0200 Subject: [PATCH 15/20] Opaque flag is immutable wrt completion only after load Part of the mechanics of how opaque types work is by setting the `opaque` flag at the objects that own them. --- compiler/src/dotty/tools/dotc/core/Flags.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 137ab0e530f4..b43d9b5dea7b 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -438,7 +438,7 @@ object Flags { val FromStartFlags: FlagSet = commonFlags( Module, Package, Method, Case, HigherKinded, Param, ParamAccessor, - Scala2ExistentialCommon, Mutable, Opaque, Touched, JavaStatic, + Scala2ExistentialCommon, Mutable, Touched, JavaStatic, OuterOrCovariant, LabelOrContravariant, CaseAccessor, Extension, NonMember, Implicit, Given, Permanent, Synthetic, SuperAccessorOrScala2x, Inline) @@ -449,7 +449,7 @@ object Flags { * is completed) */ val AfterLoadFlags: FlagSet = commonFlags( - FromStartFlags, AccessFlags, Final, AccessorOrSealed, LazyOrTrait, SelfName, JavaDefined) + FromStartFlags, Opaque, AccessFlags, Final, AccessorOrSealed, LazyOrTrait, SelfName, JavaDefined) /** Flags that are not mutated during completion when a certain * condition is satisfied From d8a51f2fb873131a2ca172465ad03a072af2f317 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Thu, 24 Oct 2019 14:47:11 +0200 Subject: [PATCH 16/20] Process Deferred flag last on unpickling Now that Deferred is conditionally immutable, if we query it along with other properly immutable flags, the query may trigger completion. This will happen if the symbol in question is also opaque and is a type. The completion will be rightfully triggered since the opaque mechanism does indeed mutate the deferred flag on opaque types. However, if e.g. we query `is(Method, butNot = Deferred)` on `opaque type B`, we may be able to return `false` on the query as soon as we see that the symbol in question is not a method, without triggering the completion. Too early completion is undesirable since completion of opaque types modifies the self-type of its owner. If the completion of an opaque type happens during unpickling of the owner itself, the self-type of the owner may be rewritten later in its completion. --- compiler/src/dotty/tools/dotc/core/Flags.scala | 5 +---- compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index b43d9b5dea7b..b2820ae6d7f3 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -456,10 +456,7 @@ object Flags { */ object ConditionallyImmutableFlags { val flagsAndConditions: List[(Flag, (given Contexts.Context) => SymDenotations.SymDenotation => Boolean)] = List( - Deferred -> { denot => - denot.is(Opaque) && denot.isType && - !denot.infoOrCompleter.isInstanceOf[SymbolLoader] // If it is loaded, we assume the opaque mechanism has already set the flags correctly - } + Deferred -> { denot => denot.is(Opaque) && denot.isType } ) val flags: FlagSet = flagsAndConditions.map(_._1) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 2be6a36203cb..87acc1c1e43d 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -677,7 +677,7 @@ class TreeUnpickler(reader: TastyReader, if (sym.isTerm && !sym.isOneOf(DeferredOrLazyOrMethod)) initsFlags = EmptyFlags else if (sym.isClass || - sym.is(Method, butNot = Deferred) && !sym.isConstructor) + sym.is(Method) && !sym.is(Deferred) && !sym.isConstructor) initsFlags &= NoInits case IMPORT => skipTree() From aebd4c56273aace68a84adbb41043460ccdf8553 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Fri, 25 Oct 2019 14:09:28 +0200 Subject: [PATCH 17/20] isLoading variable replaced with a flag for performance reasons --- .../src/dotty/tools/dotc/core/Flags.scala | 5 +++++ .../tools/dotc/core/SymDenotations.scala | 21 ++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index b2820ae6d7f3..69c5b24eecc9 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -406,6 +406,11 @@ object Flags { /** A denotation that is valid in all run-ids */ val (Permanent @ _, _, _) = newFlags(61, "") + /** Denotation is being loaded. If `Completing` is not set, + * this means this denotation was loaded from an external file. + */ + val (Loading @ _, _, _) = newFlags(62, "") + // --------- Combined Flag Sets and Conjunctions ---------------------- /** All possible flags */ diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 5db2be9b9156..9fe687f7dc9c 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -149,16 +149,6 @@ object SymDenotations { private var myPrivateWithin: Symbol = initPrivateWithin private var myAnnotations: List[Annotation] = Nil - private[this] var isLoading = false - private[this] var wasLoaded = false - - def startedLoading() = - isLoading = true - - def finishedLoading() = - isLoading = false - wasLoaded = true - /** The owner of the symbol; overridden in NoDenotation */ def owner: Symbol = maybeOwner @@ -171,12 +161,19 @@ object SymDenotations { private[dotc] final def flagsUNSAFE: FlagSet = myFlags private def setMyFlags(flags: FlagSet) = - lazy val immutableFlags = if wasLoaded then AfterLoadFlags else FromStartFlags + lazy val immutableFlags = if myInfo.isInstanceOf[SymbolLoader] then AfterLoadFlags else FromStartFlags lazy val changedImmutableFlags = (myFlags ^ flags) & immutableFlags - if myFlags.is(Touched) && !isLoading then assert(changedImmutableFlags.isEmpty, + if myFlags.is(Touched, butNot = Loading) then assert(changedImmutableFlags.isEmpty, s"Illegal mutation of flags ${changedImmutableFlags.flagsString} on completion of $this") myFlags = flags + final def startedLoading() = + myFlags |= Loading + + final def finishedLoading() = + myFlags &~= Loading + + final def flagsString(implicit ctx: Context): String = flags.flagsString /** Adapt flag set to this denotation's term or type nature */ From f7c1bb0c740353b9ac9b77b91a323784c273a16b Mon Sep 17 00:00:00 2001 From: Anatolii Date: Fri, 25 Oct 2019 14:14:28 +0200 Subject: [PATCH 18/20] Rename Touched flag to Completing "Touched" does not carry any obvious semantic meaning. "Completing" reflects the intent of when the flag should be set. --- compiler/src/dotty/tools/dotc/core/Flags.scala | 6 +++--- .../dotty/tools/dotc/core/SymDenotations.scala | 16 ++++++++-------- compiler/src/dotty/tools/dotc/core/Symbols.scala | 2 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../dotty/tools/dotc/transform/LazyVals.scala | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 69c5b24eecc9..3b53984de9f7 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -356,8 +356,8 @@ object Flags { /** Symbol is not a member of its owner */ val (NonMember @ _, _, _) = newFlags(45, "") - /** Denotation is in train of being loaded and completed, used to catch cyclic dependencies */ - val (Touched @ _, _, _) = newFlags(48, "") + /** Denotation is in train of being completed, used to catch cyclic dependencies */ + val (Completing @ _, _, _) = newFlags(48, "") /** Class has been lifted out to package level, local value has been lifted out to class level */ val (Lifted @ _, _, _) = newFlags(51, "") @@ -443,7 +443,7 @@ object Flags { val FromStartFlags: FlagSet = commonFlags( Module, Package, Method, Case, HigherKinded, Param, ParamAccessor, - Scala2ExistentialCommon, Mutable, Touched, JavaStatic, + Scala2ExistentialCommon, Mutable, Completing, JavaStatic, OuterOrCovariant, LabelOrContravariant, CaseAccessor, Extension, NonMember, Implicit, Given, Permanent, Synthetic, SuperAccessorOrScala2x, Inline) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 9fe687f7dc9c..cf6a403fca34 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -163,7 +163,7 @@ object SymDenotations { private def setMyFlags(flags: FlagSet) = lazy val immutableFlags = if myInfo.isInstanceOf[SymbolLoader] then AfterLoadFlags else FromStartFlags lazy val changedImmutableFlags = (myFlags ^ flags) & immutableFlags - if myFlags.is(Touched, butNot = Loading) then assert(changedImmutableFlags.isEmpty, + if myFlags.is(Completing, butNot = Loading) then assert(changedImmutableFlags.isEmpty, s"Illegal mutation of flags ${changedImmutableFlags.flagsString} on completion of $this") myFlags = flags @@ -259,8 +259,8 @@ object SymDenotations { println(i"${" " * indent}completing ${if (isType) "type" else "val"} $name") indent += 1 - if (myFlags.is(Touched)) throw CyclicReference(this) - myFlags |= Touched + if (myFlags.is(Completing)) throw CyclicReference(this) + myFlags |= Completing // completions.println(s"completing ${this.debugString}") try completer.complete(this)(ctx.withPhase(validFor.firstPhaseId)) @@ -275,11 +275,11 @@ object SymDenotations { } } else { - if (myFlags.is(Touched)) throw CyclicReference(this) - myFlags |= Touched + if (myFlags.is(Completing)) throw CyclicReference(this) + myFlags |= Completing completer.complete(this)(ctx.withPhase(validFor.firstPhaseId)) } - myFlags &~= Touched + myFlags &~= Completing protected[dotc] def info_=(tp: Type): Unit = { /* // DEBUG @@ -398,7 +398,7 @@ object SymDenotations { final def isCompleted: Boolean = !myInfo.isInstanceOf[LazyType] /** The denotation is in train of being completed */ - final def isCompleting: Boolean = myFlags.is(Touched) && !isCompleted + final def isCompleting: Boolean = myFlags.is(Completing) && !isCompleted /** The completer of this denotation. @pre: Denotation is not yet completed */ final def completer: LazyType = myInfo.asInstanceOf[LazyType] @@ -2245,7 +2245,7 @@ object SymDenotations { /** The type parameters computed by the completer before completion has finished */ def completerTypeParams(sym: Symbol)(implicit ctx: Context): List[TypeParamInfo] = - if (sym.is(Touched)) Nil // return `Nil` instead of throwing a cyclic reference + if (sym.is(Completing)) Nil // return `Nil` instead of throwing a cyclic reference else sym.info.typeParams def decls: Scope = myDecls diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 3ee8751a1f19..f63c9f7447fe 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -345,7 +345,7 @@ trait Symbols { this: Context => copy.denot = odenot.copySymDenotation( symbol = copy, owner = ttmap1.mapOwner(odenot.owner), - initFlags = odenot.flags &~ Touched, + initFlags = odenot.flags &~ Completing, info = completer, privateWithin = ttmap1.mapOwner(odenot.privateWithin), // since this refers to outer symbols, need not include copies (from->to) in ownermap here. annotations = odenot.annotations) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 87acc1c1e43d..25fe4d627d41 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -546,7 +546,7 @@ class TreeUnpickler(reader: TastyReader, rootd.symbol.coord = coord rootd.info = adjustIfModule( new Completer(subReader(start, end)) with SymbolLoaders.SecondCompleter) - rootd.flags = flags &~ Touched // allow one more completion + rootd.flags = flags &~ Completing // allow one more completion rootd.setPrivateWithin(privateWithin) seenRoots += rootd.symbol rootd.finishedLoading() diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index b484520aa463..1ad139b2302e 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -486,7 +486,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas def completeRoot(denot: ClassDenotation, completer: LazyType, privateWithin: Symbol): Symbol = { denot.setFlag(flags) - denot.resetFlag(Touched) // allow one more completion + denot.resetFlag(Completing) // allow one more completion // Temporary measure, as long as we do not read these classes from Tasty. // Scala-2 classes don't have NoInits set even if they are pure. We override this diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index e63a16dc658b..bcd40740eabe 100644 --- a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala @@ -179,8 +179,8 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { // need to bring containers to start of method val (holders, stats) = trees.partition { - _.symbol.flags.&~(Touched) == containerFlags - // Filtering out Touched is not required currently, as there are no LazyTypes involved here + _.symbol.flags.&~(Completing) == containerFlags + // Filtering out Completing is not required currently, as there are no LazyTypes involved here // but just to be more safe } holders:::stats From 910098b48369f2d3084ed0285914fa2642ff86d1 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Fri, 25 Oct 2019 15:09:24 +0200 Subject: [PATCH 19/20] Rename isCompleted and isCompleting methods of SymDenotation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit isCompleted is now isCompletedOrStubbed and isCompleting – isCompletingAndNotStubbed. This reflects the fact that sometimes we use a hack where we set `info` on denotations to a non-lazy type during completion to flip these predicates. This hack is possible because both of these predicates depend on checking whether the `info` is non-lazy. However, if we make these predicates with these specific names depend on the `info`'s type, their names became incorrect wrt their semantics. `isCompleting` must be true iff the `Completing` (formerly `Touched`) flag is set to true by definition of that flag. `isCompleted` must be true if we both have a concrete `info` and are not in process of being completed (since further modifications may be done by the completion process, we cannot say a denotation is completed unless this process has finished). In principle we should not use the hack in question in first place and have something more well-defined to avoid cyclic references. The bare minimum we can do right now is to rename the predicates to reflect what they do more precisely so that to avoid confusion when reading the code. --- .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../tools/dotc/core/SymDenotations.scala | 25 +++++++++++-------- .../dotty/tools/dotc/core/SymbolLoaders.scala | 4 +-- .../src/dotty/tools/dotc/core/Symbols.scala | 4 +-- .../tools/dotc/core/TypeApplications.scala | 2 +- .../dotc/interactive/InteractiveDriver.scala | 2 +- .../tools/dotc/printing/Formatting.scala | 2 +- .../tools/dotc/printing/PlainPrinter.scala | 2 +- .../src/dotty/tools/dotc/typer/Namer.scala | 2 +- .../src/dotty/tools/dotc/typer/Typer.scala | 6 ++--- 10 files changed, 28 insertions(+), 23 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index f9ad5bd52925..81f40fe7d1a1 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -277,7 +277,7 @@ class Definitions { @tu lazy val ObjectClass: ClassSymbol = { val cls = ctx.requiredClass("java.lang.Object") - assert(!cls.isCompleted, "race for completing java.lang.Object") + assert(!cls.isCompletedOrStubbed, "race for completing java.lang.Object") cls.info = ClassInfo(cls.owner.thisType, cls, AnyClass.typeRef :: Nil, newScope) cls.setFlag(NoInits) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index cf6a403fca34..c45a2eda1571 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -324,10 +324,10 @@ object SymDenotations { /** Set privateWithin, prefer setting it at symbol-creation time instead if * possible. - * @pre `isCompleting` is false, or this is a ModuleCompleter or SymbolLoader + * @pre `isCompletingAndNotStubbed` is false, or this is a ModuleCompleter or SymbolLoader */ protected[dotc] final def setPrivateWithin(pw: Symbol)(implicit ctx: Context): Unit = { - if (isCompleting) + if (isCompletingAndNotStubbed) assert(myInfo.isInstanceOf[ModuleCompleter | SymbolLoader], s"Illegal call to `setPrivateWithin($pw)` while completing $this using completer $myInfo") myPrivateWithin = pw @@ -394,11 +394,16 @@ object SymDenotations { case Nil => Nil } - /** The denotation is completed: info is not a lazy type and attributes have defined values */ - final def isCompleted: Boolean = !myInfo.isInstanceOf[LazyType] + /** The denotation's info is not set to a LazyType. This means one of + * two things: either it is completed or it is stubbed with a temporary + * info so that to avoid cyclic references. + */ + final def isCompletedOrStubbed: Boolean = !myInfo.isInstanceOf[LazyType] - /** The denotation is in train of being completed */ - final def isCompleting: Boolean = myFlags.is(Completing) && !isCompleted + /** The denotation is in train of being completed and its info is not stubbed + * with a non-lazy type. + */ + final def isCompletingAndNotStubbed: Boolean = myFlags.is(Completing) && !isCompletedOrStubbed /** The completer of this denotation. @pre: Denotation is not yet completed */ final def completer: LazyType = myInfo.asInstanceOf[LazyType] @@ -570,10 +575,10 @@ object SymDenotations { def isError: Boolean = false /** Make denotation not exist. - * @pre `isCompleting` is false, or this is a ModuleCompleter or SymbolLoader + * @pre `isCompletingAndNotStubbed` is false, or this is a ModuleCompleter or SymbolLoader */ final def markAbsent()(implicit ctx: Context): Unit = { - if (isCompleting) + if (isCompletingAndNotStubbed) assert(myInfo.isInstanceOf[ModuleCompleter | SymbolLoader], s"Illegal call to `markAbsent()` while completing $this using completer $myInfo") myInfo = NoType @@ -765,7 +770,7 @@ object SymDenotations { final def isSetter(implicit ctx: Context): Boolean = this.is(Accessor) && originalName.isSetterName && - (!isCompleted || info.firstParamTypes.nonEmpty) // to avoid being fooled by var x_= : Unit = ... + (!isCompletedOrStubbed || info.firstParamTypes.nonEmpty) // to avoid being fooled by var x_= : Unit = ... /** is this a symbol representing an import? */ final def isImport: Boolean = name == nme.IMPORT @@ -2138,7 +2143,7 @@ object SymDenotations { override def computeNPMembersNamed(name: Name)(implicit ctx: Context): PreDenotation = { def recur(pobjs: List[ClassDenotation], acc: PreDenotation): PreDenotation = pobjs match { case pcls :: pobjs1 => - if (pcls.isCompleting) recur(pobjs1, acc) + if (pcls.isCompletingAndNotStubbed) recur(pobjs1, acc) else { // A package object inherits members from `Any` and `Object` which // should not be accessible from the package prefix. diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 57cce2e48fbd..e309265156a4 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -275,7 +275,7 @@ object SymbolLoaders { assert(root is PackageClass, root) val pre = root.owner.thisType root.info = ClassInfo(pre, root.symbol.asClass, Nil, currentDecls, pre select sourceModule) - if (!sourceModule.isCompleted) + if (!sourceModule.isCompletedOrStubbed) sourceModule.completer.complete(sourceModule) val packageName = if (root.isEffectiveRoot) "" else root.fullName.mangledString @@ -351,7 +351,7 @@ abstract class SymbolLoader extends LazyType { self => } finally { def postProcess(denot: SymDenotation) = - if (!denot.isCompleted && + if (!denot.isCompletedOrStubbed && !denot.completer.isInstanceOf[SymbolLoaders.SecondCompleter]) denot.markAbsent() postProcess(root) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index f63c9f7447fe..c9d401ccb9ef 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -156,7 +156,7 @@ trait Symbols { this: Context => infoFn(module, modcls), privateWithin) val mdenot = SymDenotation( module, owner, name, modFlags | ModuleValCreationFlags, - if (cdenot.isCompleted) TypeRef(owner.thisType, modcls) + if (cdenot.isCompletedOrStubbed) TypeRef(owner.thisType, modcls) else new ModuleCompleter(modcls)) module.denot = mdenot modcls.denot = cdenot @@ -547,7 +547,7 @@ object Symbols { /** The symbol's signature if it is completed or a method, NotAMethod otherwise. */ final def signature(implicit ctx: Context): Signature = - if (lastDenot != null && (lastDenot.isCompleted || lastDenot.is(Method))) + if (lastDenot != null && (lastDenot.isCompletedOrStubbed || lastDenot.is(Method))) denot.signature else Signature.NotAMethod diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 954cd9d45c66..2cd942167eb3 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -427,7 +427,7 @@ class TypeApplications(val self: Type) extends AnyVal { * Scala2 files such as `scala.collection.generic.Mapfactory`. */ final def safeAppliedTo(args: List[Type])(implicit ctx: Context): Type = self match { - case self: TypeRef if !self.symbol.isClass && self.symbol.isCompleting => + case self: TypeRef if !self.symbol.isClass && self.symbol.isCompletingAndNotStubbed => AppliedType(self, args) case _ => appliedTo(args) diff --git a/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala b/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala index 89472bf126b3..de66dff056c1 100644 --- a/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala +++ b/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala @@ -276,7 +276,7 @@ class InteractiveDriver(val settings: List[String]) extends Driver { seen += tree tree.foreachSubTree { t => if (t.symbol.exists && t.hasType) { - if (!t.symbol.isCompleted) t.symbol.info = UnspecifiedErrorType + if (!t.symbol.isCompletedOrStubbed) t.symbol.info = UnspecifiedErrorType t.symbol.annotations.foreach { annot => /* In some cases annotations are are used on themself (possibly larger cycles). * This is the case with the java.lang.annotation.Target annotation, would end diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index 763b3e424058..2be995da5283 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -91,7 +91,7 @@ object Formatting { def isSensical(arg: Any): Boolean = arg match { case tpe: Type => tpe.exists && !tpe.isErroneous - case sym: Symbol if sym.isCompleted => + case sym: Symbol if sym.isCompletedOrStubbed => sym.info match { case _: ErrorType | TypeAlias(_: ErrorType) | NoType => false case _ => true diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 30d35b7ac00a..b352920c61f1 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -341,7 +341,7 @@ class PlainPrinter(_ctx: Context) extends Printer { if (tparams.isEmpty) Text() else ("[" ~ dclsText(tparams) ~ "]").close val selfText: Text = selfInfo match { case NoType => Text() - case sym: Symbol if !sym.isCompleted => "this: ? =>" + case sym: Symbol if !sym.isCompletedOrStubbed => "this: ? =>" case _ => "this: " ~ atPrec(InfixPrec) { toText(tp.selfType) } ~ " =>" } val trueDecls = otherDecls.filterNot(treatAsTypeArg) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 88767822ccac..b7fe77a7e45d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -811,7 +811,7 @@ class Namer { typer: Typer => } else { completeInCreationContext(denot) - if (denot.isCompleted) registerIfChild(denot) + if (denot.isCompletedOrStubbed) registerIfChild(denot) } } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 604a7c5055fb..db56e77390d8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -174,7 +174,7 @@ class Typer extends Namer } def selection(imp: ImportInfo, name: Name, checkBounds: Boolean) = - if imp.sym.isCompleting then + if imp.sym.isCompletingAndNotStubbed then ctx.warning(i"cyclic ${imp.sym}, ignored", posd.sourcePos) NoType else if unimported.nonEmpty && unimported.contains(imp.site.termSymbol) then @@ -323,7 +323,7 @@ class Typer extends Namer val namedImp = namedImportRef(curImport) if (namedImp.exists) findRefRecur(checkNewOrShadowed(namedImp, NamedImport), NamedImport, ctx)(outer) - else if (isPossibleImport(WildImport) && !curImport.sym.isCompleting) { + else if (isPossibleImport(WildImport) && !curImport.sym.isCompletingAndNotStubbed) { val wildImp = wildImportRef(curImport) if (wildImp.exists) findRefRecur(checkNewOrShadowed(wildImp, WildImport), WildImport, ctx)(outer) @@ -1213,7 +1213,7 @@ class Typer extends Namer else if (owner != cx.outer.owner && owner.isRealMethod) if (owner.isInlineMethod) (EmptyTree, errorType(NoReturnFromInlineable(owner), tree.sourcePos)) - else if (!owner.isCompleted) + else if (!owner.isCompletedOrStubbed) (EmptyTree, errorType(MissingReturnTypeWithReturnStatement(owner), tree.sourcePos)) else { val from = Ident(TermRef(NoPrefix, owner.asTerm)) From 052ff948f6aaf46b0f1d740bcd9efe40eba3896e Mon Sep 17 00:00:00 2001 From: Anatolii Date: Fri, 25 Oct 2019 15:19:28 +0200 Subject: [PATCH 20/20] Add isCompleting predicate to symbol denotations --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index c45a2eda1571..964e7c32d05e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -259,7 +259,7 @@ object SymDenotations { println(i"${" " * indent}completing ${if (isType) "type" else "val"} $name") indent += 1 - if (myFlags.is(Completing)) throw CyclicReference(this) + if (isCompleting) throw CyclicReference(this) myFlags |= Completing // completions.println(s"completing ${this.debugString}") @@ -275,7 +275,7 @@ object SymDenotations { } } else { - if (myFlags.is(Completing)) throw CyclicReference(this) + if (isCompleting) throw CyclicReference(this) myFlags |= Completing completer.complete(this)(ctx.withPhase(validFor.firstPhaseId)) } @@ -403,7 +403,10 @@ object SymDenotations { /** The denotation is in train of being completed and its info is not stubbed * with a non-lazy type. */ - final def isCompletingAndNotStubbed: Boolean = myFlags.is(Completing) && !isCompletedOrStubbed + final def isCompletingAndNotStubbed: Boolean = isCompleting && !isCompletedOrStubbed + + /** The denotation is in train of being completed */ + final def isCompleting: Boolean = myFlags.is(Completing) /** The completer of this denotation. @pre: Denotation is not yet completed */ final def completer: LazyType = myInfo.asInstanceOf[LazyType]