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 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..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) @@ -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/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 8161b6d11a6a..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, "") @@ -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 */ @@ -434,15 +439,14 @@ 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, + Module, Package, Method, Case, HigherKinded, Param, ParamAccessor, - Scala2ExistentialCommon, Mutable, Opaque, Touched, JavaStatic, + Scala2ExistentialCommon, Mutable, Completing, 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 @@ -450,7 +454,19 @@ 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 + */ + object ConditionallyImmutableFlags { + val flagsAndConditions: List[(Flag, (given Contexts.Context) => SymDenotations.SymDenotation => Boolean)] = List( + Deferred -> { denot => denot.is(Opaque) && denot.isType } + ) + + val flags: FlagSet = flagsAndConditions.map(_._1) + .foldLeft(EmptyFlags) { (accum, next) => accum | next } + } /** A value that's unstable unless complemented with a Stable flag */ diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 65aa4dc58d0d..964e7c32d05e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -160,6 +160,20 @@ object SymDenotations { */ private[dotc] final def flagsUNSAFE: FlagSet = myFlags + 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(Completing, 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 */ @@ -167,13 +181,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 @@ -184,10 +198,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 @@ -236,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 (isCompleting) throw CyclicReference(this) + myFlags |= Completing // completions.println(s"completing ${this.debugString}") try completer.complete(this)(ctx.withPhase(validFor.firstPhaseId)) @@ -252,10 +275,11 @@ object SymDenotations { } } else { - if (myFlags.is(Touched)) throw CyclicReference(this) - myFlags |= Touched + if (isCompleting) throw CyclicReference(this) + myFlags |= Completing completer.complete(this)(ctx.withPhase(validFor.firstPhaseId)) } + myFlags &~= Completing protected[dotc] def info_=(tp: Type): Unit = { /* // DEBUG @@ -300,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 @@ -370,11 +394,19 @@ 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 and its info is not stubbed + * with a non-lazy type. + */ + final def isCompletingAndNotStubbed: Boolean = isCompleting && !isCompletedOrStubbed /** The denotation is in train of being completed */ - final def isCompleting: Boolean = myFlags.is(Touched) && !isCompleted + 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] @@ -546,10 +578,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 @@ -741,7 +773,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 @@ -918,17 +950,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, @@ -2121,7 +2146,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. @@ -2228,7 +2253,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/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 5fc455f1d868..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) @@ -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 = @@ -414,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. */ diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index f70288313aa8..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 @@ -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) @@ -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 @@ -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/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/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/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index c8391e959cad..25fe4d627d41 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -541,13 +541,15 @@ 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( 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() rootd.symbol case _ => val completer = adjustIfModule(new Completer(subReader(start, end))) @@ -675,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() diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 4bfcd1b5236d..1ad139b2302e 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) @@ -482,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/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/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/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/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 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 e185ce523e5f..b7fe77a7e45d 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) @@ -762,10 +764,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 { @@ -811,7 +811,7 @@ class Namer { typer: Typer => } else { completeInCreationContext(denot) - if (denot.isCompleted) registerIfChild(denot) + if (denot.isCompletedOrStubbed) registerIfChild(denot) } } @@ -825,8 +825,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/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)) 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) ) 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 } 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