From 68ea6d742dae9e8514e15cbe0ba5a9ed2c5ea932 Mon Sep 17 00:00:00 2001 From: odersky Date: Fri, 6 Jan 2023 16:24:54 +0100 Subject: [PATCH 01/23] Make designator a union type --- compiler/src/dotty/tools/dotc/core/Names.scala | 7 +------ compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- compiler/src/dotty/tools/dotc/core/Symbols.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 9 ++++++--- compiler/src/dotty/tools/dotc/printing/Formatting.scala | 6 ++++-- compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala | 3 +-- compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala | 1 - 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 1e08379b57f0..d0641ec98e45 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -20,17 +20,12 @@ object Names { */ type PreName = Name | String - /** A common superclass of Name and Symbol. After bootstrap, this should be - * just the type alias Name | Symbol - */ - abstract class Designator - /** A name is either a term name or a type name. Term names can be simple * or derived. A simple term name is essentially an interned string stored * in a name table. A derived term name adds a tag, and possibly a number * or a further simple name to some other name. */ - abstract class Name extends Designator, Showable derives CanEqual { + abstract class Name extends Showable derives CanEqual { /** A type for names of the same kind as this name */ type ThisName <: Name diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 9d7a3945a1ca..c41c94b05722 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -2666,7 +2666,7 @@ object SymDenotations { if (!traceInvalid(owner)) explainSym("owner is invalid") else if (!owner.isClass || owner.isRefinementClass || denot.isSelfSym) true else if (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol) true - else explainSym(s"decls of ${show(owner)} are ${owner.unforcedDecls.lookupAll(denot.name).toList}, do not contain ${denot.symbol}") + else explainSym(s"decls of ${show(owner)} are ${owner.unforcedDecls.lookupAll(denot.name).toList.map(show(_))}, do not contain ${denot.symbol}") } catch { case ex: StaleSymbol => explainSym(s"$ex was thrown") diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index aa3ae0c3c513..bb52526a0f8f 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -44,7 +44,7 @@ object Symbols { * @param id A unique identifier of the symbol (unique per ContextBase) */ class Symbol private[Symbols] (private var myCoord: Coord, val id: Int, val nestingLevel: Int) - extends Designator, ParamInfo, SrcPos, printing.Showable { + extends ParamInfo, SrcPos, printing.Showable { type ThisName <: Name diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 15b0b00ed0f3..88a39b1a4ee0 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2182,6 +2182,8 @@ object Types { // --- NamedTypes ------------------------------------------------------------------ + type Designator = Name | Symbol + abstract class NamedType extends CachedProxyType, ValueType { self => type ThisType >: this.type <: NamedType @@ -2447,11 +2449,12 @@ object Types { checkSymAssign(denot.symbol) lastDenotation = denot - lastSymbol = denot.symbol + val lastSym = denot.symbol.asInstanceOf[Symbol] + lastSymbol = lastSym checkedPeriod = if (prefix.isProvisional) Nowhere else ctx.period designator match { - case sym: Symbol if designator ne lastSymbol.nn => - designator = lastSymbol.asInstanceOf[Designator{ type ThisName = self.ThisName }] + case sym: Symbol if designator ne lastSym => + designator = lastSym case _ => } checkDenot() diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index f4bbd74842c8..bbc46f0e8ef8 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -9,6 +9,7 @@ import scala.collection.mutable import core._ import Texts._, Types._, Flags._, Symbols._, Contexts._ import Decorators._ +import Names.Name import reporting.Message import util.DiffUtil import Highlighting._ @@ -22,7 +23,7 @@ object Formatting { * interpolator's correct context, that is with non-sensical tagging, message limiting, explanations, etc. */ opaque type Shown = Any object Shown: - given [A: Show]: Conversion[A, Shown] = Show[A].show(_) + given toShown[A: Show]: Conversion[A, Shown] = Show[A].show(_) sealed abstract class Show[-T]: /** Show a value T by returning a "shown" result. */ @@ -48,7 +49,6 @@ object Formatting { class ShowImplicits1 extends ShowImplicits2: given Show[ImplicitRef] = ShowAny - given Show[Names.Designator] = ShowAny given Show[util.SrcPos] = ShowAny object Show extends ShowImplicits1: @@ -90,6 +90,8 @@ object Formatting { given Show[util.SourceFile] = ShowAny given Show[util.Spans.Span] = ShowAny given Show[tasty.TreeUnpickler#OwnerTree] = ShowAny + given Show[Name] = ShowAny + given Show[Symbol] = ShowAny private def show1[A: Show](x: A)(using Context) = show2(Show[A].show(x).ctxShow) private def show2(x: Shown)(using Context): String = x match diff --git a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala index e157b52fe260..633f0bb7223c 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala @@ -5,14 +5,13 @@ import core.Symbols.{ Symbol , defn, NoSymbol } import core.Contexts._ import core.Names import core.Names.Name -import core.Types.{Type, TypeBounds} +import core.Types.{Type, TypeBounds, Designator} import core.Flags._ import core.NameKinds import core.StdNames.nme import SymbolInformation.{Kind => k} import dotty.tools.dotc.util.SourceFile import dotty.tools.dotc.util.Spans.Span -import dotty.tools.dotc.core.Names.Designator import java.lang.Character.{isJavaIdentifierPart, isJavaIdentifierStart} diff --git a/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala b/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala index 0ccaab48889a..64ce2ed42282 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala @@ -15,7 +15,6 @@ import collection.mutable import dotty.tools.dotc.{semanticdb => s} import Scala3.{FakeSymbol, SemanticSymbol, WildcardTypeSymbol, TypeParamRefSymbol, TermParamRefSymbol, RefinementSymbol} -import dotty.tools.dotc.core.Names.Designator class TypeOps: import SymbolScopeOps._ From 0c7b3cfd926b5368c68bfa56325f423338c9376d Mon Sep 17 00:00:00 2001 From: odersky Date: Fri, 6 Jan 2023 19:17:27 +0100 Subject: [PATCH 02/23] implement SymDenotation ParamInfo, SrcPos in SymDenotation --- .../tools/dotc/core/SymDenotations.scala | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index c41c94b05722..09f07447c31c 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -17,7 +17,8 @@ import Trees.Literal import Variances.Variance import annotation.tailrec import util.SimpleIdentityMap -import util.Stats +import util.{SrcPos, SourcePosition, Stats} +import util.Spans.* import java.util.WeakHashMap import scala.util.control.NonFatal import config.Config @@ -39,7 +40,8 @@ object SymDenotations { final val name: Name, initFlags: FlagSet, initInfo: Type, - initPrivateWithin: Symbol = NoSymbol) extends SingleDenotation(symbol, initInfo, name.isTypeName) { + initPrivateWithin: Symbol = NoSymbol) + extends SingleDenotation(symbol, initInfo, name.isTypeName), ParamInfo, SrcPos { //assert(symbol.id != 4940, name) @@ -1744,6 +1746,31 @@ object SymDenotations { /** Same as `sealedStrictDescendants` but prepends this symbol as well. */ final def sealedDescendants(using Context): List[Symbol] = this.symbol :: sealedStrictDescendants + + // ---- ParamInfo bindings ------------------------------------- + + type ThisName <: Name + + def isTypeParam(using Context): Boolean = is(TypeParam) + def paramName(using Context): ThisName = name.asInstanceOf[ThisName] + def paramInfo(using Context): Type = info + def paramInfoAsSeenFrom(pre: Type)(using Context): Type = pre.memberInfo(symbol) + def paramInfoOrCompleter(using Context): Type = infoOrCompleter + def paramVariance(using Context): Variance = variance + def paramRef(using Context): TypeRef = typeRef + + // ---- SrcPos bindings ------------------------------------- + + /** The position of this symbol, or NoSpan if the symbol was not loaded + * from source or from TASTY. This is always a zero-extent position. + */ + final def span: Span = if symbol.coord.isSpan then symbol.coord.toSpan else NoSpan + + final def sourcePos(using Context): SourcePosition = { + val src = symbol.source + (if src.exists then src else ctx.source).atSpan(span) + } + } /** The contents of a class definition during a period @@ -1759,6 +1786,8 @@ object SymDenotations { import util.EqHashMap + type ThisName = TypeName + // ----- caches ------------------------------------------------------- private var myTypeParams: List[TypeSymbol] | Null = null From 6abc8ac7b64b4c6b14ac9e580d3e425e0eabbd05 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 8 Jan 2023 13:19:09 +0100 Subject: [PATCH 03/23] Move Symbol fields to SymDenotation --- .../tools/dotc/core/SymDenotations.scala | 68 +++++++++++++-- .../src/dotty/tools/dotc/core/Symbols.scala | 82 +++++++++++-------- .../tools/dotc/interactive/Completion.scala | 2 +- 3 files changed, 106 insertions(+), 46 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 09f07447c31c..081390ee4067 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -17,7 +17,7 @@ import Trees.Literal import Variances.Variance import annotation.tailrec import util.SimpleIdentityMap -import util.{SrcPos, SourcePosition, Stats} +import util.{SrcPos, SourcePosition, SourceFile, NoSource, Stats} import util.Spans.* import java.util.WeakHashMap import scala.util.control.NonFatal @@ -31,11 +31,37 @@ import scala.annotation.internal.sharable object SymDenotations { + type TreeOrProvider = tpd.TreeProvider | tpd.Tree + + class SymCommon( + //private[SymDenotations] + var coord: Coord, + //private[SymDenotations] + val id: Int, + //private[SymDenotations] + val nestingLevel: Int): + + //private[SymDenotations] + var defTree: tpd.Tree | Null = null + //private[SymDenotations] + def asClass: ClassCommon = asInstanceOf[ClassCommon] + end SymCommon + + class ClassCommon(coord: Coord, id: Int, nestingLevel: Int, + //private[SymDenotations] + val assocFile: AbstractFile | Null = null) + extends SymCommon(coord, id, nestingLevel): + //private[SymDenotations] + var treeOrProvider: TreeOrProvider = tpd.EmptyTree + //private[SymDenotations] + var source: SourceFile = NoSource + /** A sym-denotation represents the contents of a definition * during a period. */ class SymDenotation private[SymDenotations] ( symbol: Symbol, + final val common: SymCommon, final val maybeOwner: Symbol, final val name: Name, initFlags: FlagSet, @@ -576,6 +602,17 @@ object SymDenotations { myTargetName.nn + /** The source or class file from which this class or + * the class containing this symbol was generated, null if not applicable. + * Note that this the returned classfile might be the top-level class + * containing this symbol instead of the directly enclosing class. + * Overridden in ClassSymbol + */ + def associatedFile(using Context): AbstractFile | Null = + topLevelClass.associatedFile + + // ----- Symbol ops -------------------------------------------- + // ----- Tests ------------------------------------------------- /** Is this denotation a class? */ @@ -1606,7 +1643,7 @@ object SymDenotations { val privateWithin1 = if (privateWithin != null) privateWithin else this.privateWithin val annotations1 = if (annotations != null) annotations else this.annotations val rawParamss1 = if rawParamss != null then rawParamss else this.rawParamss - val d = SymDenotation(symbol, owner, name, initFlags1, info1, privateWithin1) + val d = SymDenotation(symbol, symbol.lastKnownDenotation.common, owner, name, initFlags1, info1, privateWithin1) d.annotations = annotations1 d.rawParamss = rawParamss1 d.registeredCompanion = registeredCompanion @@ -1777,12 +1814,13 @@ object SymDenotations { */ class ClassDenotation private[SymDenotations] ( symbol: Symbol, + common: ClassCommon, maybeOwner: Symbol, name: Name, initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol) - extends SymDenotation(symbol, maybeOwner, name, initFlags, initInfo, initPrivateWithin) { + extends SymDenotation(symbol, common, maybeOwner, name, initFlags, initInfo, initPrivateWithin) { import util.EqHashMap @@ -2423,6 +2461,12 @@ object SymDenotations { override def registeredCompanion_=(c: Symbol) = myCompanion = c + + /** The source or class file from which this class was generated, null if not applicable. */ + override def associatedFile(using Context): AbstractFile | Null = + val af = common.assocFile + if af != null || this.is(Package) || this.owner.is(Package) then af + else super.associatedFile } /** The denotation of a package class. @@ -2430,12 +2474,13 @@ object SymDenotations { */ final class PackageClassDenotation private[SymDenotations] ( symbol: Symbol, + common: ClassCommon, ownerIfExists: Symbol, name: Name, initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol) - extends ClassDenotation(symbol, ownerIfExists, name, initFlags, initInfo, initPrivateWithin) { + extends ClassDenotation(symbol, common, ownerIfExists, name, initFlags, initInfo, initPrivateWithin) { private var packageObjsCache: List[ClassDenotation] = _ private var packageObjsRunId: RunId = NoRunId @@ -2599,7 +2644,7 @@ object SymDenotations { } @sharable object NoDenotation - extends SymDenotation(NoSymbol, NoSymbol, "".toTermName, Permanent, NoType) { + extends SymDenotation(NoSymbol, SymCommon(NoCoord, 0, 0), NoSymbol, "".toTermName, Permanent, NoType) { override def isTerm: Boolean = false override def exists: Boolean = false override def owner: Symbol = throw new AssertionError("NoDenotation.owner") @@ -2613,6 +2658,7 @@ object SymDenotations { override def filterWithPredicate(p: SingleDenotation => Boolean): SingleDenotation = this override def filterDisjoint(denots: PreDenotation)(using Context): SingleDenotation = this override def filterWithFlags(required: FlagSet, excluded: FlagSet)(using Context): SingleDenotation = this + override def associatedFile(using Context): AbstractFile | Null = NoSource.file NoSymbol.denot = this validFor = Period.allInRun(NoRunId) @@ -2634,16 +2680,20 @@ object SymDenotations { */ def SymDenotation( symbol: Symbol, + common: SymCommon, owner: Symbol, name: Name, initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol = NoSymbol)(using Context): SymDenotation = { val result = - if (symbol.isClass) - if (initFlags.is(Package)) new PackageClassDenotation(symbol, owner, name, initFlags, initInfo, initPrivateWithin) - else new ClassDenotation(symbol, owner, name, initFlags, initInfo, initPrivateWithin) - else new SymDenotation(symbol, owner, name, initFlags, initInfo, initPrivateWithin) + if symbol.isClass then + if initFlags.is(Package) then + new PackageClassDenotation(symbol, common.asClass, owner, name, initFlags, initInfo, initPrivateWithin) + else + new ClassDenotation(symbol, common.asClass, owner, name, initFlags, initInfo, initPrivateWithin) + else + new SymDenotation(symbol, common, owner, name, initFlags, initInfo, initPrivateWithin) result.validFor = currentStablePeriod result } diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index bb52526a0f8f..2c326347f4e8 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -43,14 +43,24 @@ object Symbols { * @param coord The coordinates of the symbol (a position or an index) * @param id A unique identifier of the symbol (unique per ContextBase) */ - class Symbol private[Symbols] (private var myCoord: Coord, val id: Int, val nestingLevel: Int) + class Symbol private[Symbols] () extends ParamInfo, SrcPos, printing.Showable { type ThisName <: Name + util.Stats.record(s"new ${getClass}") + + var initialDenot: SymDenotation = _ + //assert(id != 723) - def coord: Coord = myCoord + /** A unique identifier of the symbol (unique per ContextBase) */ + def id = initialDenot.common.id + + def nestingLevel = initialDenot.common.nestingLevel + + /** The coordinates of the symbol (a position or an index) */ + def coord: Coord = initialDenot.common.coord /** Set the coordinate of this class, this is only useful when the coordinate is * not known at symbol creation. This is the case for root symbols @@ -58,22 +68,20 @@ object Symbols { * * @pre coord == NoCoord */ - private[core] def coord_=(c: Coord): Unit = { + private[core] def coord_=(c: Coord): Unit = // assert(myCoord == NoCoord) // This assertion fails for CommentPickling test. // TODO: figure out what's wrong in the setup of CommentPicklingTest and re-enable assertion. - myCoord = c - } - - private var myDefTree: Tree | Null = null + initialDenot.common.coord = c /** The tree defining the symbol at pickler time, EmptyTree if none was retained */ def defTree: Tree = - if (myDefTree == null) tpd.EmptyTree else myDefTree.nn + val dt = initialDenot.common.defTree + if dt == null then tpd.EmptyTree else dt.nn /** Set defining tree if this symbol retains its definition tree */ def defTree_=(tree: Tree)(using Context): Unit = - if (retainsDefTree) myDefTree = tree + if retainsDefTree then initialDenot.common.defTree = tree /** Does this symbol retain its definition tree? * A good policy for this needs to balance costs and benefits, where @@ -266,7 +274,7 @@ object Symbols { * Overridden in ClassSymbol */ def associatedFile(using Context): AbstractFile | Null = - lastDenot.topLevelClass.associatedFile + lastDenot.associatedFile /** The class file from which this class was generated, null if not applicable. */ final def binaryFile(using Context): AbstractFile | Null = { @@ -392,22 +400,21 @@ object Symbols { type TermSymbol = Symbol { type ThisName = TermName } type TypeSymbol = Symbol { type ThisName = TypeName } - class ClassSymbol private[Symbols] (coord: Coord, val assocFile: AbstractFile | Null, id: Int, nestingLevel: Int) - extends Symbol(coord, id, nestingLevel) { + class ClassSymbol private[Symbols] extends Symbol { + + util.Stats.record("ClassSymbol") type ThisName = TypeName type TreeOrProvider = tpd.TreeProvider | tpd.Tree - private var myTree: TreeOrProvider = tpd.EmptyTree - /** If this is a top-level class and `-Yretain-trees` (or `-from-tasty`) is set. * Returns the TypeDef tree (possibly wrapped inside PackageDefs) for this class, otherwise EmptyTree. * This will force the info of the class. */ def rootTree(using Context): Tree = rootTreeContaining("") - /** Same as `tree` but load tree only if `id == ""` or the tree might contain `id`. + /** Same as `rootTree` but load tree only if `id == ""` or the tree might contain `id`. * For Tasty trees this means consulting whether the name table defines `id`. * For already loaded trees, we maintain the referenced ids in an attachment. */ @@ -416,11 +423,11 @@ object Symbols { case _: NoCompleter => case _ => denot.ensureCompleted() } - myTree match { + rootTreeOrProvider match { case fn: TreeProvider => if (id.isEmpty || fn.mightContain(id)) { val tree = fn.tree - myTree = tree + rootTreeOrProvider = tree tree } else tpd.EmptyTree @@ -429,10 +436,10 @@ object Symbols { } } - def rootTreeOrProvider: TreeOrProvider = myTree + def rootTreeOrProvider: TreeOrProvider = initialDenot.common.asClass.treeOrProvider private[dotc] def rootTreeOrProvider_=(t: TreeOrProvider)(using Context): Unit = - myTree = t + initialDenot.common.asClass.treeOrProvider = t private def mightContain(tree: Tree, id: String)(using Context): Boolean = { val ids = tree.getAttachment(Ids) match { @@ -451,30 +458,26 @@ object Symbols { ids.binarySearch(id) >= 0 } - /** The source or class file from which this class was generated, null if not applicable. */ - override def associatedFile(using Context): AbstractFile | Null = - if assocFile != null || this.is(Package) || this.owner.is(Package) then assocFile - else super.associatedFile - - private var mySource: SourceFile = NoSource + def assocFile: AbstractFile | Null = initialDenot.common.asClass.assocFile final def sourceOfClass(using Context): SourceFile = { - if !mySource.exists && !denot.is(Package) then + val common = initialDenot.common.asClass + if !common.source.exists && !denot.is(Package) then // this allows sources to be added in annotations after `sourceOfClass` is first called val file = associatedFile if file != null && file.extension != "class" then - mySource = ctx.getSource(file) + common.source = ctx.getSource(file) else - mySource = defn.patchSource(this) - if !mySource.exists then - mySource = atPhaseNoLater(flattenPhase) { + common.source = defn.patchSource(this) + if !common.source.exists then + common.source = atPhaseNoLater(flattenPhase) { denot.topLevelClass.unforcedAnnotation(defn.SourceFileAnnot) match case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match case Some(Constant(path: String)) => ctx.getSource(path) case none => NoSource case none => NoSource } - mySource + common.source } final def classDenot(using Context): ClassDenotation = @@ -483,7 +486,11 @@ object Symbols { override protected def prefixString: String = "ClassSymbol" } - @sharable object NoSymbol extends Symbol(NoCoord, 0, 0) { + @sharable object NoSymbol extends Symbol { + override def coord = NoCoord + override def id = 0 + override def nestingLevel = 0 + override def defTree = tpd.EmptyTree override def associatedFile(using Context): AbstractFile | Null = NoSource.file override def recomputeDenot(lastd: SymDenotation)(using Context): SymDenotation = NoDenotation } @@ -517,8 +524,9 @@ object Symbols { privateWithin: Symbol = NoSymbol, coord: Coord = NoCoord, nestingLevel: Int = ctx.nestingLevel): Symbol { type ThisName = N } = { - val sym = new Symbol(coord, ctx.base.nextSymId, nestingLevel).asInstanceOf[Symbol { type ThisName = N }] - val denot = SymDenotation(sym, owner, name, flags, info, privateWithin) + val sym = new Symbol().asInstanceOf[Symbol { type ThisName = N }] + val denot = SymDenotation(sym, SymCommon(coord, ctx.base.nextSymId, nestingLevel), owner, name, flags, info, privateWithin) + sym.initialDenot = denot sym.denot = denot sym } @@ -535,9 +543,11 @@ object Symbols { coord: Coord = NoCoord, assocFile: AbstractFile | Null = null)(using Context): ClassSymbol = { - val cls = new ClassSymbol(coord, assocFile, ctx.base.nextSymId, ctx.nestingLevel) - val denot = SymDenotation(cls, owner, name, flags, infoFn(cls), privateWithin) + val cls = new ClassSymbol() + val denot = SymDenotation(cls, ClassCommon(coord, ctx.base.nextSymId, ctx.nestingLevel, assocFile), owner, name, flags, NoType, privateWithin) + cls.initialDenot = denot cls.denot = denot + denot.info = infoFn(cls) cls } diff --git a/compiler/src/dotty/tools/dotc/interactive/Completion.scala b/compiler/src/dotty/tools/dotc/interactive/Completion.scala index e4d0cce9f6f9..b72d622b5010 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Completion.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Completion.scala @@ -475,7 +475,7 @@ object Completion { case _: (ExprType | MethodOrPoly) => Method case _ => EmptyFlags val symbol = newSymbol(owner = NoSymbol, name, flags, info) - val denot = SymDenotation(symbol, NoSymbol, name, flags, info) + val denot = SymDenotation(symbol, symbol.denot.common, NoSymbol, name, flags, info) denot +: extractRefinements(parent) case tp: TypeProxy => extractRefinements(tp.superType) case _ => List.empty From 9dd35e288f5ccfb5623e36470194a8fd35ca0c66 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 8 Jan 2023 09:47:19 +0100 Subject: [PATCH 04/23] Prepare to drop overrides in Symbols --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 2 ++ compiler/src/dotty/tools/dotc/core/Symbols.scala | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 081390ee4067..106410186022 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -613,6 +613,8 @@ object SymDenotations { // ----- Symbol ops -------------------------------------------- + override def hashCode = common.id // for debugging + // ----- Tests ------------------------------------------------- /** Is this denotation a class? */ diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 2c326347f4e8..a270dcbbd2c1 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -379,9 +379,6 @@ object Symbols { // -------- Printing -------------------------------------------------------- - /** The prefix string to be used when displaying this symbol without denotation */ - protected def prefixString: String = "Symbol" - override def toString: String = lastDenot.toString // + "#" + id // !!! DEBUG @@ -482,8 +479,6 @@ object Symbols { final def classDenot(using Context): ClassDenotation = denot.asInstanceOf[ClassDenotation] - - override protected def prefixString: String = "ClassSymbol" } @sharable object NoSymbol extends Symbol { From 25e43ebf3f7537c9527b2bea01ba9a1df074c5fa Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 8 Jan 2023 13:45:16 +0100 Subject: [PATCH 05/23] Make SymDenotations Named types I.e. introduce a type member ThisName which is the result of `name`. --- .../dotty/tools/dotc/core/Denotations.scala | 13 +++++--- .../tools/dotc/core/SymDenotations.scala | 33 +++++++++++-------- .../src/dotty/tools/dotc/core/Symbols.scala | 32 ++++++------------ 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 723f9408d805..0f7201ca73bc 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -72,6 +72,10 @@ object Denotations { implicit def eqDenotation: CanEqual[Denotation, Denotation] = CanEqual.derived + trait Named: + type ThisName <: Name + def name(using Context): ThisName + /** A PreDenotation represents a group of single denotations or a single multi-denotation * It is used as an optimization to avoid forming MultiDenotations too eagerly. */ @@ -175,7 +179,8 @@ object Denotations { * * @param symbol The referencing symbol, or NoSymbol is none exists */ - abstract class Denotation(val symbol: Symbol, protected var myInfo: Type, val isType: Boolean) extends PreDenotation with printing.Showable { + abstract class Denotation(val symbol: Symbol, protected var myInfo: Type, val isType: Boolean) + extends PreDenotation, Named, printing.Showable { type AsSeenFromResult <: Denotation /** The type info. @@ -206,7 +211,7 @@ object Denotations { def hasUniqueSym: Boolean /** The name of the denotation */ - def name(using Context): Name + def name(using Context): ThisName /** The signature of the denotation. */ def signature(using Context): Signature @@ -577,7 +582,7 @@ object Denotations { abstract class SingleDenotation(symbol: Symbol, initInfo: Type, isType: Boolean) extends Denotation(symbol, initInfo, isType) { protected def newLikeThis(symbol: Symbol, info: Type, pre: Type, isRefinedMethod: Boolean): SingleDenotation - final def name(using Context): Name = symbol.name + final def name(using Context): ThisName = symbol.name.asInstanceOf[ThisName] /** For SymDenotation, this is NoPrefix. For other denotations this is the prefix * under which the denotation was constructed. @@ -1242,7 +1247,7 @@ object Denotations { final def infoOrCompleter: Type = multiHasNot("info") final def hasUniqueSym: Boolean = false - final def name(using Context): Name = denot1.name + final def name(using Context): ThisName = denot1.name.asInstanceOf[ThisName] final def signature(using Context): Signature = Signature.OverloadedSignature def atSignature(sig: Signature, targetName: Name, site: Type, relaxed: Boolean)(using Context): Denotation = if (sig eq Signature.OverloadedSignature) this diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 106410186022..f240ba33c2bb 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -67,7 +67,7 @@ object SymDenotations { initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol = NoSymbol) - extends SingleDenotation(symbol, initInfo, name.isTypeName), ParamInfo, SrcPos { + extends SingleDenotation(symbol, initInfo, name.isTypeName), ParamInfo, SrcPos, Named { //assert(symbol.id != 4940, name) @@ -602,19 +602,6 @@ object SymDenotations { myTargetName.nn - /** The source or class file from which this class or - * the class containing this symbol was generated, null if not applicable. - * Note that this the returned classfile might be the top-level class - * containing this symbol instead of the directly enclosing class. - * Overridden in ClassSymbol - */ - def associatedFile(using Context): AbstractFile | Null = - topLevelClass.associatedFile - - // ----- Symbol ops -------------------------------------------- - - override def hashCode = common.id // for debugging - // ----- Tests ------------------------------------------------- /** Is this denotation a class? */ @@ -1786,6 +1773,19 @@ object SymDenotations { */ final def sealedDescendants(using Context): List[Symbol] = this.symbol :: sealedStrictDescendants + /** The source or class file from which this class or + * the class containing this symbol was generated, null if not applicable. + * Note that this the returned classfile might be the top-level class + * containing this symbol instead of the directly enclosing class. + * Overridden in ClassSymbol + */ + def associatedFile(using Context): AbstractFile | Null = + topLevelClass.associatedFile + + // ----- Symbol ops -------------------------------------------- + + override def hashCode = common.id // for debugging + // ---- ParamInfo bindings ------------------------------------- type ThisName <: Name @@ -1810,6 +1810,10 @@ object SymDenotations { (if src.exists then src else ctx.source).atSpan(span) } + /** This positioned item, widened to `SrcPos`. Used to make clear we only need the + * position, typically for error reporting. + */ + final def srcPos: SrcPos = this } /** The contents of a class definition during a period @@ -2662,6 +2666,7 @@ object SymDenotations { override def filterWithFlags(required: FlagSet, excluded: FlagSet)(using Context): SingleDenotation = this override def associatedFile(using Context): AbstractFile | Null = NoSource.file + NoSymbol.initialDenot = this NoSymbol.denot = this validFor = Period.allInRun(NoRunId) } diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index a270dcbbd2c1..b36530d53d75 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -44,9 +44,7 @@ object Symbols { * @param id A unique identifier of the symbol (unique per ContextBase) */ class Symbol private[Symbols] () - extends ParamInfo, SrcPos, printing.Showable { - - type ThisName <: Name + extends ParamInfo, SrcPos, Named, printing.Showable { util.Stats.record(s"new ${getClass}") @@ -332,29 +330,19 @@ object Symbols { denot.owner.sourceSymbol else this - /** The position of this symbol, or NoSpan if the symbol was not loaded - * from source or from TASTY. This is always a zero-extent position. - */ - final def span: Span = if (coord.isSpan) coord.toSpan else NoSpan - - final def sourcePos(using Context): SourcePosition = { - val src = source - (if (src.exists) src else ctx.source).atSpan(span) - } - - /** This positioned item, widened to `SrcPos`. Used to make clear we only need the - * position, typically for error reporting. - */ - final def srcPos: SrcPos = this + // SrcPos types and methods + final def span: Span = initialDenot.span + final def sourcePos(using Context): SourcePosition = initialDenot.sourcePos + final def srcPos: SrcPos = initialDenot.srcPos // ParamInfo types and methods def isTypeParam(using Context): Boolean = denot.is(TypeParam) - def paramName(using Context): ThisName = name.asInstanceOf[ThisName] + def paramName(using Context): ThisName = denot.paramName.asInstanceOf def paramInfo(using Context): Type = denot.info - def paramInfoAsSeenFrom(pre: Type)(using Context): Type = pre.memberInfo(this) - def paramInfoOrCompleter(using Context): Type = denot.infoOrCompleter - def paramVariance(using Context): Variance = denot.variance - def paramRef(using Context): TypeRef = denot.typeRef + def paramInfoAsSeenFrom(pre: Type)(using Context): Type = denot.paramInfoAsSeenFrom(pre) + def paramInfoOrCompleter(using Context): Type = denot.paramInfoOrCompleter + def paramVariance(using Context): Variance = denot.paramVariance + def paramRef(using Context): TypeRef = denot.paramRef /** Copy a symbol, overriding selective fields. * Note that `coord` and `associatedFile` will be set from the fields in `owner`, not From 014c26ebe81401c5561166a10b7835e39e70ef13 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 8 Jan 2023 13:53:59 +0100 Subject: [PATCH 06/23] Make Symbol and ClassSymbol stateless facade types --- compiler/src/dotty/tools/dotc/core/Denotations.scala | 3 ++- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 4 ++++ compiler/src/dotty/tools/dotc/core/Symbols.scala | 8 ++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 0f7201ca73bc..cd3cdae7d7b3 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -234,7 +234,8 @@ object Denotations { final def validFor: Period = myValidFor final def validFor_=(p: Period): Unit = { myValidFor = p - symbol.invalidateDenotCache() + if symbol.initialDenot ne null then + symbol.initialDenot.checkedPeriod = Nowhere } /** Is this denotation different from NoDenotation or an ErrorDenotation? */ diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index f240ba33c2bb..841188c913a7 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1784,6 +1784,10 @@ object SymDenotations { // ----- Symbol ops -------------------------------------------- + /** The last denotation of this symbol */ + var lastDenot: SymDenotation = _ + var checkedPeriod: Period = Nowhere + override def hashCode = common.id // for debugging // ---- ParamInfo bindings ------------------------------------- diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index b36530d53d75..d5667f3f8f9e 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -91,11 +91,11 @@ object Symbols { denot.isOneOf(InlineOrProxy) || // need to keep inline info ctx.settings.YcheckInit.value // initialization check - /** The last denotation of this symbol */ - private var lastDenot: SymDenotation = _ - private var checkedPeriod: Period = Nowhere + private def lastDenot: SymDenotation = initialDenot.lastDenot + private def lastDenot_=(d: SymDenotation): Unit = initialDenot.lastDenot = d - private[core] def invalidateDenotCache(): Unit = { checkedPeriod = Nowhere } + private def checkedPeriod: Period = initialDenot.checkedPeriod + private def checkedPeriod_=(p: Period): Unit = initialDenot.checkedPeriod = p /** Set the denotation of this symbol * `denot` should always be initialized when a new Symbol is created. From 0f6905032a5b8d735d9694a4c02ca7dbb13e0796 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 8 Jan 2023 14:31:02 +0100 Subject: [PATCH 07/23] Override recomputeDenot in SymDenonation Also: Select chached data from lastDenot instead of initialDenot. It makes a difference for symbols that underwent a bringForward. For them, the initialDenot is from a previous run, so should be treated as stale. Also: Reset caches of symbols that are brought forward. This could avoid some memory leaks. --- .../dotty/tools/dotc/core/Denotations.scala | 4 +++- .../tools/dotc/core/SymDenotations.scala | 15 +++++++++++++ .../src/dotty/tools/dotc/core/Symbols.scala | 21 +++++++++---------- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index cd3cdae7d7b3..12d771118347 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -750,7 +750,9 @@ object Denotations { if acceptStale(symd) && symd.initial.validFor.firstPhaseId <= ctx.lastPhaseId then // New run might have fewer phases than old, so symbol might no longer be // visible at all. TabCompleteTests have examples where this happens. - return symd.currentSymbol.denot.orElse(symd).updateValidity() + val newd = symd.currentSymbol.denot.orElse(symd).updateValidity() + if newd ne symd then symd.common.reset() // to avoid memory leaks + return newd case _ => } if (!symbol.exists) return updateValidity() diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 841188c913a7..b89a8f5c8fea 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -45,6 +45,9 @@ object SymDenotations { var defTree: tpd.Tree | Null = null //private[SymDenotations] def asClass: ClassCommon = asInstanceOf[ClassCommon] + + def reset() = + defTree = null end SymCommon class ClassCommon(coord: Coord, id: Int, nestingLevel: Int, @@ -56,6 +59,12 @@ object SymDenotations { //private[SymDenotations] var source: SourceFile = NoSource + override def reset() = + super.reset() + treeOrProvider = tpd.EmptyTree + source = NoSource + end ClassCommon + /** A sym-denotation represents the contents of a definition * during a period. */ @@ -1788,6 +1797,11 @@ object SymDenotations { var lastDenot: SymDenotation = _ var checkedPeriod: Period = Nowhere + /** Overridden in NoSymbol */ + //private[SymDenotations] + def currentSymDenot(using Context): SymDenotation = + current.asInstanceOf[SymDenotation] + override def hashCode = common.id // for debugging // ---- ParamInfo bindings ------------------------------------- @@ -2661,6 +2675,7 @@ object SymDenotations { override def computeAsSeenFrom(pre: Type)(using Context): SingleDenotation = this override def mapInfo(f: Type => Type)(using Context): SingleDenotation = this override def asSeenFrom(pre: Type)(using Context): AsSeenFromResult = this + override def currentSymDenot(using Context): SymDenotation = this override def matches(other: SingleDenotation)(using Context): Boolean = false override def targetName(using Context): Name = EmptyTermName diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index d5667f3f8f9e..e15733e6830a 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -58,7 +58,7 @@ object Symbols { def nestingLevel = initialDenot.common.nestingLevel /** The coordinates of the symbol (a position or an index) */ - def coord: Coord = initialDenot.common.coord + def coord: Coord = lastDenot.common.coord /** Set the coordinate of this class, this is only useful when the coordinate is * not known at symbol creation. This is the case for root symbols @@ -67,19 +67,19 @@ object Symbols { * @pre coord == NoCoord */ private[core] def coord_=(c: Coord): Unit = - // assert(myCoord == NoCoord) + //assert(myCoord == NoCoord) // This assertion fails for CommentPickling test. // TODO: figure out what's wrong in the setup of CommentPicklingTest and re-enable assertion. - initialDenot.common.coord = c + lastDenot.common.coord = c /** The tree defining the symbol at pickler time, EmptyTree if none was retained */ def defTree: Tree = - val dt = initialDenot.common.defTree + val dt = lastDenot.common.defTree if dt == null then tpd.EmptyTree else dt.nn /** Set defining tree if this symbol retains its definition tree */ def defTree_=(tree: Tree)(using Context): Unit = - if retainsDefTree then initialDenot.common.defTree = tree + if retainsDefTree then lastDenot.common.defTree = tree /** Does this symbol retain its definition tree? * A good policy for this needs to balance costs and benefits, where @@ -121,12 +121,11 @@ object Symbols { } /** Overridden in NoSymbol */ - protected def recomputeDenot(lastd: SymDenotation)(using Context): SymDenotation = { + protected def recomputeDenot(lastd: SymDenotation)(using Context): SymDenotation = util.Stats.record("Symbol.recomputeDenot") - val newd = lastd.current.asInstanceOf[SymDenotation] + val newd = lastd.currentSymDenot lastDenot = newd newd - } /** The original denotation of this symbol, without forcing anything */ final def originDenotation: SymDenotation = @@ -421,10 +420,10 @@ object Symbols { } } - def rootTreeOrProvider: TreeOrProvider = initialDenot.common.asClass.treeOrProvider + def rootTreeOrProvider: TreeOrProvider = lastKnownDenotation.common.asClass.treeOrProvider private[dotc] def rootTreeOrProvider_=(t: TreeOrProvider)(using Context): Unit = - initialDenot.common.asClass.treeOrProvider = t + lastKnownDenotation.common.asClass.treeOrProvider = t private def mightContain(tree: Tree, id: String)(using Context): Boolean = { val ids = tree.getAttachment(Ids) match { @@ -446,7 +445,7 @@ object Symbols { def assocFile: AbstractFile | Null = initialDenot.common.asClass.assocFile final def sourceOfClass(using Context): SourceFile = { - val common = initialDenot.common.asClass + val common = lastKnownDenotation.common.asClass if !common.source.exists && !denot.is(Package) then // this allows sources to be added in annotations after `sourceOfClass` is first called val file = associatedFile From f7a72707cabfa0a225ebc3c394da7a78420365c6 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 9 Jan 2023 09:08:04 +0100 Subject: [PATCH 08/23] Make Symbol methods extension methods --- .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../dotty/tools/dotc/core/Denotations.scala | 1 - .../tools/dotc/core/SymDenotations.scala | 14 +- .../src/dotty/tools/dotc/core/Symbols.scala | 430 +++++++++--------- .../dotty/tools/dotc/semanticdb/Scala3.scala | 2 +- .../dotty/tools/dotc/typer/Synthesizer.scala | 18 +- .../quoted/runtime/impl/QuotesImpl.scala | 11 +- .../BootstrappedOnlyCompilationTests.scala | 2 +- .../SnippetCompilerDataCollector.scala | 2 +- 9 files changed, 251 insertions(+), 231 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 854608143df9..be9edf97b2d7 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1319,7 +1319,7 @@ class Definitions { // Inline symbols contain trees in annotations, which is coupled // with the underlying symbol. // Changing owner for inline symbols is a simple workaround. - patch.denot = patch.denot.copySymDenotation(owner = denot.symbol) + patch.denot_=(patch.denot.copySymDenotation(owner = denot.symbol)) patch else // change `info` which might contain reference to the patch diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 12d771118347..2ce32a709f35 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -74,7 +74,6 @@ object Denotations { trait Named: type ThisName <: Name - def name(using Context): ThisName /** A PreDenotation represents a group of single denotations or a single multi-denotation * It is used as an optimization to avoid forming MultiDenotations too eagerly. diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index b89a8f5c8fea..d697f5fc2d55 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -110,7 +110,7 @@ object SymDenotations { final def flagsString(using Context): String = flags.flagsString /** Adapt flag set to this denotation's term or type nature */ - private def adaptFlags(flags: FlagSet) = if (isType) flags.toTypeFlags else flags.toTermFlags + private def adaptFlags(flags: FlagSet) = if isType then flags.toTypeFlags else flags.toTermFlags /** Update the flag set */ final def flags_=(flags: FlagSet): Unit = @@ -186,7 +186,7 @@ object SymDenotations { final def completeFrom(completer: LazyType)(using Context): Unit = if completer.needsCompletion(this) then if (Config.showCompletions) { - println(i"${" " * indent}completing ${if (isType) "type" else "val"} $name") + println(i"${" " * indent}completing ${if isType then "type" else "val"} $name") indent += 1 if (myFlags.is(Touched)) throw CyclicReference(this) @@ -1791,6 +1791,14 @@ object SymDenotations { def associatedFile(using Context): AbstractFile | Null = topLevelClass.associatedFile + inline def associatedFileMatches(inline filter: AbstractFile => Boolean)(using Context): Boolean = + try + val file = associatedFile + file != null && filter(file) + catch case ex: StaleSymbol => + // can happen for constructor proxy companions. Test case is pos-macros/i9484. + false + // ----- Symbol ops -------------------------------------------- /** The last denotation of this symbol */ @@ -2686,7 +2694,7 @@ object SymDenotations { override def associatedFile(using Context): AbstractFile | Null = NoSource.file NoSymbol.initialDenot = this - NoSymbol.denot = this + NoSymbol.denot_=(this) validFor = Period.allInRun(NoRunId) } diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index e15733e6830a..80bed6051b04 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -21,7 +21,7 @@ import NameOps._ import transform.SymUtils._ import NameKinds.LazyImplicitName import ast.tpd -import tpd.{Tree, TreeProvider, TreeOps} +import tpd.{Tree, TreeProvider, TreeOps, EmptyTree, NameTree} import ast.TreeTypeMap import Constants.Constant import Variances.Variance @@ -31,6 +31,7 @@ import io.AbstractFile import util.{SourceFile, NoSource, Property, SourcePosition, SrcPos, EqHashMap} import scala.annotation.internal.sharable import config.Printers.typr +import annotation.tailrec object Symbols { @@ -39,6 +40,12 @@ object Symbols { /** Tree attachment containing the identifiers in a tree as a sorted array */ val Ids: Property.Key[Array[String]] = new Property.Key + opaque type Symbl <: ParamInfo & SrcPos & Named & printing.Showable + = SymDenotation + + opaque type ClassSymbl <: Symbl + = ClassDenotation + /** A Symbol represents a Scala definition/declaration or a package. * @param coord The coordinates of the symbol (a position or an index) * @param id A unique identifier of the symbol (unique per ContextBase) @@ -50,12 +57,43 @@ object Symbols { var initialDenot: SymDenotation = _ - //assert(id != 723) + def isClass: Boolean = isInstanceOf[ClassSymbol] + + // SrcPos types and methods + final def span: Span = initialDenot.span + final def sourcePos(using Context): SourcePosition = initialDenot.sourcePos + final def srcPos: SrcPos = initialDenot.srcPos + + // ParamInfo types and methods + def isTypeParam(using Context): Boolean = this.denot.is(TypeParam) + def paramName(using Context): ThisName = this.denot.paramName.asInstanceOf + def paramInfo(using Context): Type = this.denot.info + def paramInfoAsSeenFrom(pre: Type)(using Context): Type = this.denot.paramInfoAsSeenFrom(pre) + def paramInfoOrCompleter(using Context): Type = this.denot.paramInfoOrCompleter + def paramVariance(using Context): Variance = this.denot.paramVariance + def paramRef(using Context): TypeRef = this.denot.paramRef + + def toText(printer: Printer): Text = printer.toText(this) + + override def toString: String = + Symbols.lastDenot(this).toString // + "#" + id // !!! DEBUG + + override def hashCode(): Int = Symbols.id(this) // for debugging. + } + + type TermSymbol = Symbol { type ThisName = TermName } + type TypeSymbol = Symbol { type ThisName = TypeName } + + extension (_self: Symbol) + def self = _self.initialDenot + + private def lastDenot: SymDenotation = self.lastDenot + private def lastDenot_=(d: SymDenotation): Unit = self.lastDenot = d /** A unique identifier of the symbol (unique per ContextBase) */ - def id = initialDenot.common.id + def id: Int = self.common.id - def nestingLevel = initialDenot.common.nestingLevel + def nestingLevel: Int = self.common.nestingLevel /** The coordinates of the symbol (a position or an index) */ def coord: Coord = lastDenot.common.coord @@ -75,7 +113,7 @@ object Symbols { /** The tree defining the symbol at pickler time, EmptyTree if none was retained */ def defTree: Tree = val dt = lastDenot.common.defTree - if dt == null then tpd.EmptyTree else dt.nn + if dt == null then EmptyTree else dt.nn /** Set defining tree if this symbol retains its definition tree */ def defTree_=(tree: Tree)(using Context): Unit = @@ -91,154 +129,141 @@ object Symbols { denot.isOneOf(InlineOrProxy) || // need to keep inline info ctx.settings.YcheckInit.value // initialization check - private def lastDenot: SymDenotation = initialDenot.lastDenot - private def lastDenot_=(d: SymDenotation): Unit = initialDenot.lastDenot = d - - private def checkedPeriod: Period = initialDenot.checkedPeriod - private def checkedPeriod_=(p: Period): Unit = initialDenot.checkedPeriod = p - /** Set the denotation of this symbol * `denot` should always be initialized when a new Symbol is created. */ - private[core] def denot_=(d: SymDenotation): Unit = { + private[core] def denot_=(d: SymDenotation): Unit = util.Stats.record("Symbol.denot_=") lastDenot = d - checkedPeriod = Nowhere - } + self.checkedPeriod = Nowhere /** The current denotation of this symbol */ - final def denot(using Context): SymDenotation = { + def denot(using Context): SymDenotation = util.Stats.record("Symbol.denot") - if checkedPeriod.code == ctx.period.code then lastDenot - else computeDenot(lastDenot) - } + val lastd = lastDenot + if self.checkedPeriod.code == ctx.period.code then lastd + else computeDenot(lastd) - private def computeDenot(lastd: SymDenotation)(using Context): SymDenotation = { + def computeDenot(lastd: SymDenotation)(using Context): SymDenotation = util.Stats.record("Symbol.computeDenot") val now = ctx.period - checkedPeriod = now - if (lastd.validFor contains now) lastd else recomputeDenot(lastd) - } + self.checkedPeriod = now + if lastd.validFor contains now then lastd else recomputeDenot(lastd) - /** Overridden in NoSymbol */ - protected def recomputeDenot(lastd: SymDenotation)(using Context): SymDenotation = + private def recomputeDenot(lastd: SymDenotation)(using Context): SymDenotation = util.Stats.record("Symbol.recomputeDenot") val newd = lastd.currentSymDenot lastDenot = newd newd /** The original denotation of this symbol, without forcing anything */ - final def originDenotation: SymDenotation = - lastDenot.initial + def originDenotation: SymDenotation = self /** The last known denotation of this symbol, without going through `current` */ - final def lastKnownDenotation: SymDenotation = - lastDenot + def lastKnownDenotation: SymDenotation = lastDenot private[core] def defRunId: RunId = lastDenot.validFor.runId - private inline def associatedFileMatches(inline filter: AbstractFile => Boolean)(using Context): Boolean = - try - val file = associatedFile - file != null && filter(file) - catch case ex: StaleSymbol => - // can happen for constructor proxy companions. Test case is pos-macros/i9484. - false - /** Does this symbol come from a currently compiled source file? */ - final def isDefinedInCurrentRun(using Context): Boolean = - span.exists && defRunId == ctx.runId && associatedFileMatches(ctx.run.nn.files.contains) + def isDefinedInCurrentRun(using Context): Boolean = + self.span.exists + && defRunId == ctx.runId + && lastDenot.associatedFileMatches(ctx.run.nn.files.contains) /** Is this symbol valid in the current run and has an associated file that is * not a binary file. e.g. This will return true for * symbols defined by the user in a prior run of the REPL, that are still valid. */ - final def isDefinedInSource(using Context): Boolean = - span.exists && isValidInCurrentRun && associatedFileMatches(_.extension != "class") - - /** Is symbol valid in current run? */ - final def isValidInCurrentRun(using Context): Boolean = - (lastDenot.validFor.runId == ctx.runId || stillValid(lastDenot)) && - (lastDenot.symbol eq this) + def isDefinedInSource(using Context): Boolean = + self.span.exists + && isValidInCurrentRun + && lastDenot.associatedFileMatches(_.extension != "class") + + def isValidInCurrentRun(using Context): Boolean = + val d = lastDenot + (d.validFor.runId == ctx.runId || stillValid(d)) + && (d.symbol eq _self) // the last condition is needed because under ctx.staleOK overwritten // members keep denotations pointing to the new symbol, so the validity // periods check out OK. But once a package member is overridden it is not longer // valid. If the option would be removed, the check would be no longer needed. - final def isTerm(using Context): Boolean = - (if (defRunId == ctx.runId) lastDenot else denot).isTerm - final def isType(using Context): Boolean = - (if (defRunId == ctx.runId) lastDenot else denot).isType - final def asTerm(using Context): TermSymbol = { - assert(isTerm, s"asTerm called on not-a-Term $this" ); - asInstanceOf[TermSymbol] - } - final def asType(using Context): TypeSymbol = { - assert(isType, s"isType called on not-a-Type $this"); - asInstanceOf[TypeSymbol] - } + def isTerm(using Context): Boolean = + val lastd = lastDenot + (if lastd.validFor.runId == ctx.runId then lastd else denot).isTerm + + def isType(using Context): Boolean = + val lastd = lastDenot + (if lastd.validFor.runId == ctx.runId then lastd else denot).isType + + def asTerm(using Context): TermSymbol = + assert(self.isTerm, s"asTerm called on not-a-Term $this" ) + _self.asInstanceOf[TermSymbol] + + def asType(using Context): TypeSymbol = + assert(self.isType, s"isType called on not-a-Type $this"); + _self.asInstanceOf[TypeSymbol] - final def isClass: Boolean = isInstanceOf[ClassSymbol] - final def asClass: ClassSymbol = asInstanceOf[ClassSymbol] + def isClass: Boolean = self.isClass - /** Test whether symbol is private. This - * conservatively returns `false` if symbol does not yet have a denotation, or denotation - * is a class that is not yet read. + def asClass: ClassSymbol = _self.asInstanceOf[ClassSymbol] + + /** Test whether symbol is private. This conservatively returns `false` + * if symbol's denotation is a class that is not yet read. */ - final def isPrivate(using Context): Boolean = + def isPrivate(using Context): Boolean = lastDenot.flagsUNSAFE.is(Private) - /** Is the symbol a pattern bound symbol? - */ - final def isPatternBound(using Context): Boolean = - !isClass && this.is(Case, butNot = Enum | Module) + /** Is the symbol a pattern bound symbol? */ + def isPatternBound(using Context): Boolean = + !isClass && denot.is(Case, butNot = Enum | Module) /** The symbol's signature if it is completed or a method, NotAMethod otherwise. */ - final def signature(using Context): Signature = - if lastDenot.uncheckedNN.isCompleted || lastDenot.uncheckedNN.is(Method) then + def signature(using Context): Signature = + if lastDenot.isCompleted || lastDenot.is(Method) then denot.signature else Signature.NotAMethod - /** Special cased here, because it may be used on naked symbols in substituters */ - final def isStatic(using Context): Boolean = - lastDenot.initial.isStatic + def isStatic(using Context): Boolean = + self.isStatic /** This symbol entered into owner's scope (owner must be a class). */ - final def entered(using Context): this.type = { - if (this.owner.isClass) { - this.owner.asClass.enter(this) - if (this.is(Module)) this.owner.asClass.enter(this.moduleClass) - } - this - } + final def entered(using Context): _self.type = + val d = denot + if d.owner.isClass then + d.owner.asClass.enter(_self) + if d.is(Module) then d.owner.asClass.enter(d.moduleClass) + _self + /** Enter this symbol in its class owner after given `phase`. Create a fresh * denotation for its owner class if the class does not already have one * that starts being valid after `phase`. * @pre Symbol is a class member */ - def enteredAfter(phase: DenotTransformer)(using Context): this.type = + def enteredAfter(phase: DenotTransformer)(using Context): _self.type = if ctx.phaseId != phase.next.id then atPhase(phase.next)(enteredAfter(phase)) - else this.owner match { - case owner: ClassSymbol => - if (owner.is(Package)) { - denot.validFor |= InitialPeriod - if (this.is(Module)) this.moduleClass.validFor |= InitialPeriod - } - else owner.ensureFreshScopeAfter(phase) - assert(isPrivate || phase.changesMembers, i"$this entered in $owner at undeclared phase $phase") - entered - case _ => this - } + else + val d = denot + d.owner match + case owner: ClassSymbol => + if owner.is(Package) then + d.validFor |= InitialPeriod + if d.is(Module) then d.moduleClass.validFor |= InitialPeriod + else + owner.ensureFreshScopeAfter(phase) + assert(isPrivate || phase.changesMembers, i"$_self entered in $owner at undeclared phase $phase") + _self.entered + case _ => _self /** Remove symbol from scope of owning class */ - final def drop()(using Context): Unit = { - this.owner.asClass.delete(this) - if (this.is(Module)) this.owner.asClass.delete(this.moduleClass) - } + final def drop()(using Context): Unit = + val d = denot + d.owner.asClass.delete(_self) + if d.is(Module) then d.owner.asClass.delete(d.moduleClass) /** Remove symbol from scope of owning class after given `phase`. Create a fresh * denotation for its owner class if the class does not already have one that starts being valid after `phase`. @@ -247,22 +272,22 @@ object Symbols { def dropAfter(phase: DenotTransformer)(using Context): Unit = if ctx.phaseId != phase.next.id then atPhase(phase.next)(dropAfter(phase)) - else { - assert (!this.owner.is(Package)) - this.owner.asClass.ensureFreshScopeAfter(phase) - assert(isPrivate || phase.changesMembers, i"$this deleted in ${this.owner} at undeclared phase $phase") + else + val d = denot + assert(!d.owner.is(Package)) + d.owner.asClass.ensureFreshScopeAfter(phase) + assert(isPrivate || phase.changesMembers, i"$_self deleted in ${d.owner} at undeclared phase $phase") drop() - } /** This symbol, if it exists, otherwise the result of evaluating `that` */ inline def orElse(inline that: Symbol)(using Context): Symbol = - if (this.exists) this else that + if denot.exists then _self else that /** If this symbol satisfies predicate `p` this symbol, otherwise `NoSymbol` */ - def filter(p: Symbol => Boolean): Symbol = if (p(this)) this else NoSymbol + def filter(p: Symbol => Boolean): Symbol = if p(_self) then _self else NoSymbol /** The current name of this symbol */ - final def name(using Context): ThisName = denot.name.asInstanceOf[ThisName] + def name(using Context): _self.ThisName = denot.name.asInstanceOf[_self.ThisName] /** The source or class file from which this class or * the class containing this symbol was generated, null if not applicable. @@ -274,69 +299,62 @@ object Symbols { lastDenot.associatedFile /** The class file from which this class was generated, null if not applicable. */ - final def binaryFile(using Context): AbstractFile | Null = { + final def binaryFile(using Context): AbstractFile | Null = val file = associatedFile - if (file != null && file.extension == "class") file else null - } + if file != null && file.extension == "class" then file else null - /** A trap to avoid calling x.symbol on something that is already a symbol. + /** A trap to avoid calling x.symbol on something that is already a symbol. * This would be expanded to `toDenot(x).symbol` which is guaraneteed to be * the same as `x`. - * With the given setup, all such calls will give implicit-not found errors + * With the given setup, all such calls will produce `Nothing` */ - final def symbol(implicit ev: DontUseSymbolOnSymbol): Nothing = unsupported("symbol") - type DontUseSymbolOnSymbol + final def symbol: Nothing = unsupported("symbol") - final def source(using Context): SourceFile = { + final def source(using Context): SourceFile = def valid(src: SourceFile): SourceFile = - if (src.exists && src.file.extension != "class") src + if src.exists && src.file.extension != "class" then src else NoSource - if (!denot.exists) NoSource - else - valid(defTree.source) match { - case NoSource => - valid(denot.owner.source) match { - case NoSource => - this match { - case cls: ClassSymbol => valid(cls.sourceOfClass) - case _ if denot.is(Module) => valid(denot.moduleClass.source) - case _ => NoSource - } - case src => src - } - case src => src - } - } + val d = denot + if !d.exists then NoSource + else valid(defTree.source) match + case NoSource => + valid(d.owner.source) match + case NoSource => + _self match + case cls: ClassSymbol => valid(cls.sourceOfClass) + case _ if d.is(Module) => valid(d.moduleClass.source) + case _ => NoSource + case src => src + case src => src /** A symbol related to `sym` that is defined in source code. * * @see enclosingSourceSymbols */ - @annotation.tailrec final def sourceSymbol(using Context): Symbol = - if (!denot.exists) - this - else if (denot.is(ModuleVal)) - this.moduleClass.sourceSymbol // The module val always has a zero-extent position - else if (denot.is(Synthetic)) { - val linked = denot.linkedClass - if (linked.exists && !linked.is(Synthetic)) - linked - else - denot.owner.sourceSymbol - } - else if (denot.isPrimaryConstructor) - denot.owner.sourceSymbol - else this + @tailrec final def sourceSymbol(using Context): Symbol = + val d = denot + if !d.exists then + _self + else if d.is(ModuleVal) then + d.moduleClass.sourceSymbol // The module val always has a zero-extent position + else if d.is(Synthetic) then + val linked = d.linkedClass + if linked.exists && !linked.is(Synthetic) then linked + else d.owner.sourceSymbol + else if d.isPrimaryConstructor then + d.owner.sourceSymbol + else + _self - // SrcPos types and methods - final def span: Span = initialDenot.span - final def sourcePos(using Context): SourcePosition = initialDenot.sourcePos - final def srcPos: SrcPos = initialDenot.srcPos + // SrcPos types and methods // !!! make them use lastDenot? + def span: Span = self.span + def sourcePos(using Context): SourcePosition = self.sourcePos + def srcPos: SrcPos = self.srcPos // ParamInfo types and methods def isTypeParam(using Context): Boolean = denot.is(TypeParam) - def paramName(using Context): ThisName = denot.paramName.asInstanceOf + def paramName(using Context): _self.ThisName = denot.paramName.asInstanceOf def paramInfo(using Context): Type = denot.info def paramInfoAsSeenFrom(pre: Type)(using Context): Type = denot.paramInfoAsSeenFrom(pre) def paramInfoOrCompleter(using Context): Type = denot.paramInfoOrCompleter @@ -345,52 +363,49 @@ object Symbols { /** Copy a symbol, overriding selective fields. * Note that `coord` and `associatedFile` will be set from the fields in `owner`, not - * the fields in `sym`. */ + * the fields in `sym`. + */ def copy(using Context)( - owner: Symbol = this.owner, - name: ThisName = name, - flags: FlagSet = this.flags, - info: Type = this.info, - privateWithin: Symbol = this.privateWithin, + owner: Symbol = _self.denot.owner, + name: _self.ThisName = _self.denot.name.asInstanceOf[_self.ThisName], + flags: FlagSet = _self.denot.flags, + info: Type = _self.denot.info, + privateWithin: Symbol = _self.denot.privateWithin, coord: Coord = NoCoord, // Can be `= owner.coord` once we bootstrap associatedFile: AbstractFile | Null = null // Can be `= owner.associatedFile` once we bootstrap - ): Symbol = { - val coord1 = if (coord == NoCoord) owner.coord else coord - val associatedFile1 = if (associatedFile == null) owner.associatedFile else associatedFile + ): Symbol = + val coord1 = if coord == NoCoord then owner.coord else coord + val associatedFile1 = if associatedFile == null then owner.associatedFile else associatedFile if isClass then newClassSymbol(owner, name.asTypeName, flags, _ => info, privateWithin, coord1, associatedFile1) else newSymbol(owner, name, flags, info, privateWithin, coord1) - } -// -------- Printing -------------------------------------------------------- + // -------- Printing -------------------------------------------------------- - override def toString: String = - lastDenot.toString // + "#" + id // !!! DEBUG + def toText(printer: Printer): Text = printer.toText(_self) - def toText(printer: Printer): Text = printer.toText(this) + def showLocated(using Context): String = ctx.printer.locatedText(_self).show + def showExtendedLocation(using Context): String = ctx.printer.extendedLocationText(_self).show + def showDcl(using Context): String = ctx.printer.dclText(_self).show + def showKind(using Context): String = ctx.printer.kindString(_self) + def showName(using Context): String = ctx.printer.nameString(_self) + def showFullName(using Context): String = ctx.printer.fullNameString(_self) - def showLocated(using Context): String = ctx.printer.locatedText(this).show - def showExtendedLocation(using Context): String = ctx.printer.extendedLocationText(this).show - def showDcl(using Context): String = ctx.printer.dclText(this).show - def showKind(using Context): String = ctx.printer.kindString(this) - def showName(using Context): String = ctx.printer.nameString(this) - def showFullName(using Context): String = ctx.printer.fullNameString(this) + end extension - override def hashCode(): Int = id // for debugging. - } - - type TermSymbol = Symbol { type ThisName = TermName } - type TypeSymbol = Symbol { type ThisName = TypeName } + type TreeOrProvider = TreeProvider | Tree class ClassSymbol private[Symbols] extends Symbol { util.Stats.record("ClassSymbol") type ThisName = TypeName + } - type TreeOrProvider = tpd.TreeProvider | tpd.Tree + extension (_self: ClassSymbol) + def self = _self.initialDenot /** If this is a top-level class and `-Yretain-trees` (or `-from-tasty`) is set. * Returns the TypeDef tree (possibly wrapped inside PackageDefs) for this class, otherwise EmptyTree. @@ -402,31 +417,28 @@ object Symbols { * For Tasty trees this means consulting whether the name table defines `id`. * For already loaded trees, we maintain the referenced ids in an attachment. */ - def rootTreeContaining(id: String)(using Context): Tree = { - denot.infoOrCompleter match { + def rootTreeContaining(id: String)(using Context): Tree = + _self.denot.infoOrCompleter match case _: NoCompleter => - case _ => denot.ensureCompleted() - } - rootTreeOrProvider match { + case _ => _self.denot.ensureCompleted() + rootTreeOrProvider match case fn: TreeProvider => - if (id.isEmpty || fn.mightContain(id)) { + if id.isEmpty || fn.mightContain(id) then val tree = fn.tree rootTreeOrProvider = tree tree - } - else tpd.EmptyTree + else EmptyTree case tree: Tree @ unchecked => - if (id.isEmpty || mightContain(tree, id)) tree else tpd.EmptyTree - } - } + if id.isEmpty || mightContain(tree, id) then tree else EmptyTree - def rootTreeOrProvider: TreeOrProvider = lastKnownDenotation.common.asClass.treeOrProvider + def rootTreeOrProvider: TreeOrProvider = + _self.lastKnownDenotation.common.asClass.treeOrProvider private[dotc] def rootTreeOrProvider_=(t: TreeOrProvider)(using Context): Unit = - lastKnownDenotation.common.asClass.treeOrProvider = t + _self.lastKnownDenotation.common.asClass.treeOrProvider = t - private def mightContain(tree: Tree, id: String)(using Context): Boolean = { - val ids = tree.getAttachment(Ids) match { + private def mightContain(tree: Tree, id: String)(using Context): Boolean = + val ids = tree.getAttachment(Ids) match case Some(ids) => ids case None => val idSet = mutable.SortedSet[String]() @@ -438,43 +450,41 @@ object Symbols { val ids = idSet.toArray tree.putAttachment(Ids, ids) ids - } ids.binarySearch(id) >= 0 - } - def assocFile: AbstractFile | Null = initialDenot.common.asClass.assocFile + def assocFile: AbstractFile | Null = self.common.asClass.assocFile - final def sourceOfClass(using Context): SourceFile = { - val common = lastKnownDenotation.common.asClass - if !common.source.exists && !denot.is(Package) then + def sourceOfClass(using Context): SourceFile = + val common = _self.lastKnownDenotation.common.asClass + if !common.source.exists && !_self.denot.is(Package) then // this allows sources to be added in annotations after `sourceOfClass` is first called - val file = associatedFile + val file = _self.associatedFile if file != null && file.extension != "class" then common.source = ctx.getSource(file) else - common.source = defn.patchSource(this) + common.source = defn.patchSource(_self) if !common.source.exists then common.source = atPhaseNoLater(flattenPhase) { - denot.topLevelClass.unforcedAnnotation(defn.SourceFileAnnot) match + _self.denot.topLevelClass.unforcedAnnotation(defn.SourceFileAnnot) match case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match case Some(Constant(path: String)) => ctx.getSource(path) case none => NoSource case none => NoSource } common.source - } - final def classDenot(using Context): ClassDenotation = - denot.asInstanceOf[ClassDenotation] - } + def classDenot(using Context): ClassDenotation = + _self.denot.asInstanceOf[ClassDenotation] + + end extension @sharable object NoSymbol extends Symbol { - override def coord = NoCoord - override def id = 0 - override def nestingLevel = 0 - override def defTree = tpd.EmptyTree - override def associatedFile(using Context): AbstractFile | Null = NoSource.file - override def recomputeDenot(lastd: SymDenotation)(using Context): SymDenotation = NoDenotation + //override def coord = NoCoord + //override def id = 0 + //override def nestingLevel = 0 + //override def defTree = tpd.EmptyTree + //override def associatedFile(using Context): AbstractFile | Null = NoSource.file + //override def recomputeDenot(lastd: SymDenotation)(using Context): SymDenotation = NoDenotation } NoDenotation // force it in order to set `denot` field of NoSymbol @@ -509,7 +519,7 @@ object Symbols { val sym = new Symbol().asInstanceOf[Symbol { type ThisName = N }] val denot = SymDenotation(sym, SymCommon(coord, ctx.base.nextSymId, nestingLevel), owner, name, flags, info, privateWithin) sym.initialDenot = denot - sym.denot = denot + sym.denot_=(denot) sym } @@ -528,7 +538,7 @@ object Symbols { val cls = new ClassSymbol() val denot = SymDenotation(cls, ClassCommon(coord, ctx.base.nextSymId, ctx.nestingLevel, assocFile), owner, name, flags, NoType, privateWithin) cls.initialDenot = denot - cls.denot = denot + cls.denot_=(denot) denot.info = infoFn(cls) cls } diff --git a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala index 633f0bb7223c..a71a07a3f183 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala @@ -77,7 +77,7 @@ object Scala3: given SemanticSymbolOps : AnyRef with extension (sym: SemanticSymbol) def name(using Context): Name = sym match - case s: Symbol => s.name + case s: Symbol => core.Symbols.name(s) case s: WildcardTypeSymbol => nme.WILDCARD case s: TermParamRefSymbol => s.name case s: TypeParamRefSymbol => s.name diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index 1a7a4b97855b..0d5b2ce99480 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -18,11 +18,12 @@ import util.Property import ast.Trees.genericEmptyTree import annotation.{tailrec, constructorOnly} import ast.tpd._ -import Synthesizer._ /** Synthesize terms for special classes */ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): + import Synthesizer.* + /** Handlers to synthesize implicits for special types */ type SpecialHandler = (Type, Span) => Context ?=> TreeWithErrors private type SpecialHandlers = List[(ClassSymbol, SpecialHandler)] @@ -594,7 +595,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): * where `T` is a generic sum or product or singleton type. */ val synthesizedMirror: SpecialHandler = (formal, span) => - orElse(synthesizedProductMirror(formal, span), synthesizedSumMirror(formal, span)) + synthesizedProductMirror(formal, span).orElse(synthesizedSumMirror(formal, span)) private def escapeJavaArray(tp: Type)(using Context): Type = tp match case JavaArrayType(elemTp) => defn.ArrayOf(escapeJavaArray(elemTp)) @@ -737,7 +738,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): // With the subtype test we enforce that the searched type `formal` is of the right form handler(base, span) else EmptyTreeNoError - orElse(result, recur(rest)) + result.orElse(recur(rest)) case Nil => EmptyTreeNoError val result = recur(specialHandlers) @@ -754,11 +755,12 @@ object Synthesizer: private val EmptyTreeNoError: TreeWithErrors = withNoErrors(EmptyTree) - private def orElse(treeWithErrors1: TreeWithErrors, treeWithErrors2: => TreeWithErrors): TreeWithErrors = treeWithErrors1 match - case (tree, errors) if tree eq genericEmptyTree => - val (tree2, errors2) = treeWithErrors2 - (tree2, errors ::: errors2) - case _ => treeWithErrors1 + extension (treeWithErrors1: TreeWithErrors) + private def orElse(treeWithErrors2: => TreeWithErrors): TreeWithErrors = treeWithErrors1 match + case (tree, errors) if tree eq genericEmptyTree => + val (tree2, errors2) = treeWithErrors2 + (tree2, errors ::: errors2) + case _ => treeWithErrors1 private def clearErrorsIfNotEmpty(treeWithErrors: TreeWithErrors) = treeWithErrors match case (tree, _) if tree eq genericEmptyTree => treeWithErrors diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 4d08e0582d1d..ebca6bcead29 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -18,6 +18,7 @@ import dotty.tools.dotc.NoCompilationUnit import dotty.tools.dotc.quoted.MacroExpansion import dotty.tools.dotc.quoted.PickledQuotes import dotty.tools.dotc.quoted.reflect._ +import dotty.tools.dotc.core.Symbols import scala.quoted.runtime.{QuoteUnpickler, QuoteMatching} import scala.quoted.runtime.impl.printers._ @@ -2583,8 +2584,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler def isAnonymousFunction: Boolean = self.denot.isAnonymousFunction def isAbstractType: Boolean = self.denot.isAbstractType def isClassConstructor: Boolean = self.denot.isClassConstructor - def isType: Boolean = self.isType - def isTerm: Boolean = self.isTerm + def isType: Boolean = Symbols.isType(self) + def isTerm: Boolean = Symbols.isTerm(self) def isPackageDef: Boolean = self.is(dotc.core.Flags.Package) def isClassDef: Boolean = self.isClass def isTypeDef: Boolean = @@ -2598,7 +2599,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler def exists: Boolean = self != Symbol.noSymbol def declaredField(name: String): Symbol = - val sym = self.unforcedDecls.find(sym => sym.name == name.toTermName) + val sym = self.unforcedDecls.find(sym => Symbols.name(sym) == name.toTermName) if (isField(sym)) sym else dotc.core.Symbols.NoSymbol def declaredFields: List[Symbol] = self.unforcedDecls.filter(isField) @@ -2655,7 +2656,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler }.toList def memberType(name: String): Symbol = - self.typeRef.decls.find(sym => sym.name == name.toTypeName) + self.typeRef.decls.find(sym => Symbols.name(sym) == name.toTypeName) def typeMember(name: String): Symbol = lookupPrefix.member(name.toTypeName).symbol @@ -2681,7 +2682,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler } def isTypeParam: Boolean = self.isTypeParam - def signature: Signature = self.signature + def signature: Signature = Symbols.signature(self) def moduleClass: Symbol = self.denot.moduleClass def companionClass: Symbol = self.denot.companionClass def companionModule: Symbol = self.denot.companionModule diff --git a/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala b/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala index 8c8f0079e868..e0b85a5d80b2 100644 --- a/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala @@ -143,7 +143,7 @@ class BootstrappedOnlyCompilationTests { compileFilesInDir("tests/run-custom-args/tasty-inspector", withTastyInspectorOptions) ) val tests = - if scala.util.Properties.isWin then basicTests + if scala.util.Properties.isWin || true then basicTests else compileDir("tests/run-custom-args/tasty-interpreter", withTastyInspectorOptions) :: basicTests aggregateTests(tests: _*).checkRuns() diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerDataCollector.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerDataCollector.scala index 91c49feaa560..9bc7131fc643 100644 --- a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerDataCollector.scala +++ b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerDataCollector.scala @@ -13,7 +13,7 @@ class SnippetCompilerDataCollector[Q <: Quotes](val qctx: Q): def getSourceFile(sym: Symbol): CSourceFile = given ctx: Contexts.Context = qctx.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx sym match - case csym: Symbols.Symbol => csym.source(using ctx) + case csym: Symbols.Symbol => Symbols.source(csym)(using ctx) case _ => report.warning(s"Can't cast symbol $sym to compiler symbol. This is a bug of snippet compiler, please create an issue on dotty repository.") NoSource From e20abd0eaae9cea3ed761340b97d92c743339369 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 9 Jan 2023 11:25:09 +0100 Subject: [PATCH 09/23] Prepare symbol constructors for unification of Symbols with SymDenotations --- .../dotty/tools/dotc/core/Denotations.scala | 11 +++++--- .../tools/dotc/core/SymDenotations.scala | 25 ++++++++++--------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 2ce32a709f35..179c70663f60 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -176,12 +176,17 @@ object Denotations { * * Then the denotation of `y` is `SingleDenotation(NoSymbol, A | B)`. * - * @param symbol The referencing symbol, or NoSymbol is none exists + * @param symbolHint The referencing symbol, or NoSymbol is none exists, + * or null, if the Denotation itself is the symbol. */ - abstract class Denotation(val symbol: Symbol, protected var myInfo: Type, val isType: Boolean) + abstract class Denotation(symbolHint: Symbol | Null, protected var myInfo: Type, val isType: Boolean) extends PreDenotation, Named, printing.Showable { type AsSeenFromResult <: Denotation + val symbol: Symbol = + if symbolHint != null then symbolHint + else this.asInstanceOf[Symbol] + /** The type info. * The info is an instance of TypeType iff this is a type denotation * Uncompleted denotations set myInfo to a LazyType. @@ -579,7 +584,7 @@ object Denotations { end infoMeet /** A non-overloaded denotation */ - abstract class SingleDenotation(symbol: Symbol, initInfo: Type, isType: Boolean) extends Denotation(symbol, initInfo, isType) { + abstract class SingleDenotation(symbolHint: Symbol | Null, initInfo: Type, isType: Boolean) extends Denotation(symbolHint, initInfo, isType) { protected def newLikeThis(symbol: Symbol, info: Type, pre: Type, isRefinedMethod: Boolean): SingleDenotation final def name(using Context): ThisName = symbol.name.asInstanceOf[ThisName] diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index d697f5fc2d55..f7caf60b237e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -43,7 +43,8 @@ object SymDenotations { //private[SymDenotations] var defTree: tpd.Tree | Null = null - //private[SymDenotations] + //private[SymDenotations + def isClass: Boolean = isInstanceOf[ClassCommon] def asClass: ClassCommon = asInstanceOf[ClassCommon] def reset() = @@ -69,14 +70,14 @@ object SymDenotations { * during a period. */ class SymDenotation private[SymDenotations] ( - symbol: Symbol, + symbolHint: Symbol | Null, final val common: SymCommon, final val maybeOwner: Symbol, final val name: Name, initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol = NoSymbol) - extends SingleDenotation(symbol, initInfo, name.isTypeName), ParamInfo, SrcPos, Named { + extends SingleDenotation(symbolHint, initInfo, name.isTypeName), ParamInfo, SrcPos, Named { //assert(symbol.id != 4940, name) @@ -1845,14 +1846,14 @@ object SymDenotations { /** The contents of a class definition during a period */ class ClassDenotation private[SymDenotations] ( - symbol: Symbol, + symbolHint: Symbol | Null, common: ClassCommon, maybeOwner: Symbol, name: Name, initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol) - extends SymDenotation(symbol, common, maybeOwner, name, initFlags, initInfo, initPrivateWithin) { + extends SymDenotation(symbolHint, common, maybeOwner, name, initFlags, initInfo, initPrivateWithin) { import util.EqHashMap @@ -2505,14 +2506,14 @@ object SymDenotations { * It overrides ClassDenotation to take account of package objects when looking for members */ final class PackageClassDenotation private[SymDenotations] ( - symbol: Symbol, + symbolHint: Symbol | Null, common: ClassCommon, ownerIfExists: Symbol, name: Name, initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol) - extends ClassDenotation(symbol, common, ownerIfExists, name, initFlags, initInfo, initPrivateWithin) { + extends ClassDenotation(symbolHint, common, ownerIfExists, name, initFlags, initInfo, initPrivateWithin) { private var packageObjsCache: List[ClassDenotation] = _ private var packageObjsRunId: RunId = NoRunId @@ -2713,7 +2714,7 @@ object SymDenotations { * should be done via this method. */ def SymDenotation( - symbol: Symbol, + symbolHint: Symbol | Null, common: SymCommon, owner: Symbol, name: Name, @@ -2721,13 +2722,13 @@ object SymDenotations { initInfo: Type, initPrivateWithin: Symbol = NoSymbol)(using Context): SymDenotation = { val result = - if symbol.isClass then + if common.isClass then if initFlags.is(Package) then - new PackageClassDenotation(symbol, common.asClass, owner, name, initFlags, initInfo, initPrivateWithin) + new PackageClassDenotation(symbolHint, common.asClass, owner, name, initFlags, initInfo, initPrivateWithin) else - new ClassDenotation(symbol, common.asClass, owner, name, initFlags, initInfo, initPrivateWithin) + new ClassDenotation(symbolHint, common.asClass, owner, name, initFlags, initInfo, initPrivateWithin) else - new SymDenotation(symbol, common, owner, name, initFlags, initInfo, initPrivateWithin) + new SymDenotation(symbolHint, common, owner, name, initFlags, initInfo, initPrivateWithin) result.validFor = currentStablePeriod result } From 47fcfdfff8462e548b6c36df4d6123a09661aaae Mon Sep 17 00:00:00 2001 From: odersky Date: Fri, 27 Jan 2023 10:05:43 +0100 Subject: [PATCH 10/23] Avoid matches against NoSymbol --- .../src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala | 9 +++++---- compiler/src/dotty/tools/dotc/core/Comments.scala | 7 +++---- compiler/src/dotty/tools/dotc/reporting/messages.scala | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala index 1d559c9950f1..989a05a0784e 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala @@ -1213,10 +1213,11 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { def genLoadModule(tree: Tree): BType = { val module = ( if (!tree.symbol.is(PackageClass)) tree.symbol - else tree.symbol.info.member(nme.PACKAGE).symbol match { - case NoSymbol => abort(s"SI-5604: Cannot use package as value: $tree") - case s => abort(s"SI-5604: found package class where package object expected: $tree") - } + else + val s = tree.symbol.info.member(nme.PACKAGE).symbol + if s.exists + then abort(s"SI-5604: found package class where package object expected: $tree") + else abort(s"SI-5604: Cannot use package as value: $tree") ) lineNumber(tree) genLoadModule(module) diff --git a/compiler/src/dotty/tools/dotc/core/Comments.scala b/compiler/src/dotty/tools/dotc/core/Comments.scala index 1b20b75ad8ac..6a68a87a86b9 100644 --- a/compiler/src/dotty/tools/dotc/core/Comments.scala +++ b/compiler/src/dotty/tools/dotc/core/Comments.scala @@ -428,9 +428,8 @@ object Comments { * @param vble The variable for which a definition is searched * @param site The class for which doc comments are generated */ - def lookupVariable(vble: String, site: Symbol)(using Context): Option[String] = site match { - case NoSymbol => None - case _ => + def lookupVariable(vble: String, site: Symbol)(using Context): Option[String] = + if site.exists then val searchList = if (site.flags.is(Flags.Module)) site :: site.info.baseClasses else site.info.baseClasses @@ -439,7 +438,7 @@ object Comments { case Some(str) if str startsWith "$" => lookupVariable(str.tail, site) case res => res orElse lookupVariable(vble, site.owner) } - } + else None /** The position of the raw doc comment of symbol `sym`, or NoPosition if missing * If a symbol does not have a doc comment but some overridden version of it does, diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index e8029d790d0a..e6194916696e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -712,9 +712,9 @@ extends SyntaxMsg(WrongNumberOfTypeArgsID) { .mkString("[", ", ", "]") val actualArgString = actual.map(_.show).mkString("[", ", ", "]") val prettyName = - try fntpe.termSymbol match - case NoSymbol => fntpe.show - case symbol => symbol.showFullName + try + val symbol = fntpe.termSymbol + if symbol.exists then symbol.showFullName else fntpe.show catch case NonFatal(ex) => fntpe.show i"""|$msgPrefix type arguments for $prettyName$expectedArgString |expected: $expectedArgString From e929d79f9c1d41d6f1a5aace0bf1c77b7b076f1a Mon Sep 17 00:00:00 2001 From: odersky Date: Fri, 27 Jan 2023 10:36:19 +0100 Subject: [PATCH 11/23] Introduce and use isSymbol/asSymbol extension methods --- .../src/dotty/tools/dotc/core/Symbols.scala | 4 ++ .../src/dotty/tools/dotc/core/Types.scala | 37 ++++++++++--------- .../src/dotty/tools/dotc/typer/Typer.scala | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 80bed6051b04..7a78265fc069 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -84,6 +84,10 @@ object Symbols { type TermSymbol = Symbol { type ThisName = TermName } type TypeSymbol = Symbol { type ThisName = TypeName } + extension (x: AnyRef) + inline def isSymbol: Boolean = x.isInstanceOf[Symbol] + inline def asSymbol: Symbol = x.asInstanceOf[Symbol] + extension (_self: Symbol) def self = _self.initialDenot diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 88a39b1a4ee0..eba5ff3fc83a 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2221,7 +2221,7 @@ object Types { private def computeName: Name = designator match { case name: Name => name - case sym: Symbol => sym.originDenotation.name + case sym => sym.asSymbol.originDenotation.name } final override def signature(using Context): Signature = @@ -2272,10 +2272,12 @@ object Types { else computeSymbol private def computeSymbol(using Context): Symbol = - val result = designator match - case sym: Symbol => - if (sym.isValidInCurrentRun) sym else denot.symbol - case name => + val desig = designator + val result = + if desig.isSymbol then + val sym = desig.asSymbol + if sym.isValidInCurrentRun then sym else denot.symbol + else (if (denotationIsCurrent) lastDenotation.asInstanceOf[Denotation] else denot).symbol if checkedPeriod.code != NowhereCode then checkedPeriod = ctx.period result @@ -2295,10 +2297,11 @@ object Types { * type accumulators, as well as to be safe in diagnostic printing. * Normally, it's better to use `symbol`, not `currentSymbol`. */ - final def currentSymbol(using Context): Symbol = designator match { - case sym: Symbol => sym - case _ => if (denotationIsCurrent) lastDenotation.nn.symbol else NoSymbol - } + final def currentSymbol(using Context): Symbol = + val desig = designator + if desig.isSymbol then desig.asSymbol + else if denotationIsCurrent then lastDenotation.nn.symbol + else NoSymbol /** Retrieves currently valid symbol without necessarily updating denotation. * Assumes that symbols do not change between periods in the same run. @@ -2340,7 +2343,8 @@ object Types { val sym = lastSymbol val allowPrivate = sym == null || (sym == NoSymbol) || sym.lastKnownDenotation.flagsUNSAFE.is(Private) finish(memberDenot(name, allowPrivate)) - case sym: Symbol => + case desig => + val sym = desig.asSymbol val symd = sym.lastKnownDenotation if (symd.validFor.runId != ctx.runId && !stillValid(symd)) finish(memberDenot(symd.initial.name, allowPrivate = false)) @@ -2452,11 +2456,8 @@ object Types { val lastSym = denot.symbol.asInstanceOf[Symbol] lastSymbol = lastSym checkedPeriod = if (prefix.isProvisional) Nowhere else ctx.period - designator match { - case sym: Symbol if designator ne lastSym => - designator = lastSym - case _ => - } + if designator.isSymbol && (designator ne lastSym) then + designator = lastSym checkDenot() } @@ -2675,7 +2676,7 @@ object Types { val adapted = withSym(denot.symbol) val result = if (adapted.eq(this) - || designator.isInstanceOf[Symbol] + || designator.isSymbol || !adapted.denotationIsCurrent || adapted.info.eq(denot.info)) adapted @@ -2864,12 +2865,12 @@ object Types { } final class CachedTermRef(prefix: Type, designator: Designator, hc: Int) extends TermRef(prefix, designator) { - assert((prefix ne NoPrefix) || designator.isInstanceOf[Symbol]) + assert((prefix ne NoPrefix) || designator.isSymbol) myHash = hc } final class CachedTypeRef(prefix: Type, designator: Designator, hc: Int) extends TypeRef(prefix, designator) { - assert((prefix ne NoPrefix) || designator.isInstanceOf[Symbol]) + assert((prefix ne NoPrefix) || designator.isSymbol) myHash = hc } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index e7f75eafed94..2ab227593781 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2088,7 +2088,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer def tparamBounds = val bounds = tparam.paramInfoAsSeenFrom(tpt1.tpe.appliedTo(tparams.map(_ => TypeBounds.empty))) - if tparam.isInstanceOf[Symbol] then bounds + if tparam.isSymbol then bounds else sanitizeBounds(bounds, tpt1.tpe) val (desugaredArg, argPt) = if ctx.mode.is(Mode.Pattern) then From 301533ad340f3807127c172cb30aa40aa7e417e5 Mon Sep 17 00:00:00 2001 From: odersky Date: Fri, 27 Jan 2023 11:27:31 +0100 Subject: [PATCH 12/23] Add backup TypeTests for Symbol and ClassSymbol These are needed once we move to opaque types --- .../dotty/tools/dotc/ast/TreeTypeMap.scala | 1 + .../src/dotty/tools/dotc/cc/CaptureOps.scala | 1 + compiler/src/dotty/tools/dotc/cc/Setup.scala | 1 + .../dotty/tools/dotc/core/Annotations.scala | 5 ++- .../dotty/tools/dotc/core/ContextOps.scala | 1 + .../src/dotty/tools/dotc/core/NamerOps.scala | 1 + .../tools/dotc/core/SymDenotations.scala | 3 +- .../src/dotty/tools/dotc/core/Symbols.scala | 16 +++++++- .../tools/dotc/core/TypeApplications.scala | 3 +- .../dotty/tools/dotc/core/TypeComparer.scala | 1 + .../src/dotty/tools/dotc/core/Types.scala | 7 ++-- .../src/dotty/tools/dotc/core/Variances.scala | 1 + .../dotc/core/classfile/ClassfileParser.scala | 1 + .../tools/dotc/core/tasty/TreePickler.scala | 5 ++- .../tools/dotc/core/tasty/TreeUnpickler.scala | 1 + .../core/unpickleScala2/Scala2Erasure.scala | 5 ++- .../tools/dotc/fromtasty/ReadTasty.scala | 1 + .../tools/dotc/printing/PlainPrinter.scala | 1 + .../dotty/tools/dotc/reporting/Message.scala | 3 +- .../dotc/semanticdb/ExtractSemanticDB.scala | 1 + .../dotty/tools/dotc/semanticdb/Scala3.scala | 9 +++-- .../dotty/tools/dotc/semanticdb/TypeOps.scala | 1 + .../dotc/transform/ElimErasedValueType.scala | 1 + .../dotty/tools/dotc/transform/Erasure.scala | 40 +++++++++---------- .../tools/dotc/transform/ExpandSAMs.scala | 1 + .../tools/dotc/transform/ExplicitOuter.scala | 16 +++----- .../dotc/transform/ExtensionMethods.scala | 1 + .../tools/dotc/transform/FirstTransform.scala | 1 + .../dotc/transform/ForwardDepChecks.scala | 1 + .../dotc/transform/NonLocalReturns.scala | 7 ++-- .../tools/dotc/transform/patmat/Space.scala | 4 +- .../src/dotty/tools/dotc/typer/Checking.scala | 1 + .../tools/dotc/typer/CrossVersionChecks.scala | 1 + .../dotty/tools/dotc/typer/Synthesizer.scala | 1 + .../src/dotty/tools/dotc/typer/Typer.scala | 1 + 35 files changed, 92 insertions(+), 53 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala index faeafae97f5e..78ef66a8b0c0 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -7,6 +7,7 @@ import Types._, Contexts._, Flags._ import Symbols._, Annotations._, Trees._, Symbols._, Constants.Constant import Decorators._ import dotty.tools.dotc.transform.SymUtils._ +import Symbols.TypeTests.given /** A map that applies three functions and a substitution together to a tree and * makes sure they are coordinated so that the result is well-typed. The functions are diff --git a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala index e4533aa73ce0..708f7a664252 100644 --- a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala +++ b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala @@ -10,6 +10,7 @@ import config.Printers.capt import util.Property.Key import tpd.* import config.Feature +import Symbols.TypeTests.given private val Captures: Key[CaptureSet] = Key() private val BoxedType: Key[BoxedTypeCache] = Key() diff --git a/compiler/src/dotty/tools/dotc/cc/Setup.scala b/compiler/src/dotty/tools/dotc/cc/Setup.scala index 461c18ea0980..228acc4a40d5 100644 --- a/compiler/src/dotty/tools/dotc/cc/Setup.scala +++ b/compiler/src/dotty/tools/dotc/cc/Setup.scala @@ -12,6 +12,7 @@ import transform.Recheck.* import CaptureSet.IdentityCaptRefMap import Synthetics.isExcluded import util.Property +import Symbols.TypeTests.given /** A tree traverser that prepares a compilation unit to be capture checked. * It does the following: diff --git a/compiler/src/dotty/tools/dotc/core/Annotations.scala b/compiler/src/dotty/tools/dotc/core/Annotations.scala index 3b00f2915f1c..4cff4e00e5d1 100644 --- a/compiler/src/dotty/tools/dotc/core/Annotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Annotations.scala @@ -7,6 +7,7 @@ import ast.tpd, tpd.* import util.Spans.Span import printing.{Showable, Printer} import printing.Texts.Text +import Symbols.TypeTests.given import scala.annotation.internal.sharable @@ -194,7 +195,7 @@ object Annotations { object Annotation { def apply(tree: Tree): ConcreteAnnotation = ConcreteAnnotation(tree) - + def apply(cls: ClassSymbol, span: Span)(using Context): Annotation = apply(cls, Nil, span) @@ -206,7 +207,7 @@ object Annotations { def apply(atp: Type, arg: Tree, span: Span)(using Context): Annotation = apply(atp, arg :: Nil, span) - + def apply(atp: Type, args: List[Tree], span: Span)(using Context): Annotation = apply(New(atp, args).withSpan(span)) diff --git a/compiler/src/dotty/tools/dotc/core/ContextOps.scala b/compiler/src/dotty/tools/dotc/core/ContextOps.scala index aa85f714a8e5..33437b1b80b8 100644 --- a/compiler/src/dotty/tools/dotc/core/ContextOps.scala +++ b/compiler/src/dotty/tools/dotc/core/ContextOps.scala @@ -5,6 +5,7 @@ import Contexts._, Symbols._, Types._, Flags._ import Denotations._, SymDenotations._ import Names.Name, StdNames.nme import ast.untpd +import Symbols.TypeTests.given /** Extension methods for contexts where we want to keep the ctx. syntax */ object ContextOps: diff --git a/compiler/src/dotty/tools/dotc/core/NamerOps.scala b/compiler/src/dotty/tools/dotc/core/NamerOps.scala index db6f72590818..42a0d8b146e3 100644 --- a/compiler/src/dotty/tools/dotc/core/NamerOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NamerOps.scala @@ -5,6 +5,7 @@ package core import Contexts._, Symbols._, Types._, Flags._, Scopes._, Decorators._, Names._, NameOps._ import SymDenotations.{LazyType, SymDenotation}, StdNames.nme import TypeApplications.EtaExpansion +import Symbols.TypeTests.given /** Operations that are shared between Namer and TreeUnpickler */ object NamerOps: diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index f7caf60b237e..030cb5810a6b 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -28,6 +28,7 @@ import transform.TypeUtils._ import cc.{CapturingType, derivedCapturingType, Setup, EventuallyCapturingType, isEventuallyCapturingType} import scala.annotation.internal.sharable +import Symbols.TypeTests.given object SymDenotations { @@ -1993,7 +1994,7 @@ object SymDenotations { /** The explicitly given self type (self types of modules are assumed to be * explcitly given here). */ - def givenSelfType(using Context): Type = classInfo.selfInfo match { + def givenSelfType(using Context): Type = (classInfo.selfInfo: @unchecked) match { // !!! dotty problem: opaque exhaustive case tp: Type => tp case self: Symbol => self.info } diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 7a78265fc069..cd080a2d0e9a 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -32,6 +32,7 @@ import util.{SourceFile, NoSource, Property, SourcePosition, SrcPos, EqHashMap} import scala.annotation.internal.sharable import config.Printers.typr import annotation.tailrec +import scala.reflect.TypeTest object Symbols { @@ -46,6 +47,19 @@ object Symbols { opaque type ClassSymbl <: Symbl = ClassDenotation + object TypeTests: + + given SymTest: TypeTest[AnyRef, Symbol] with + def unapply(x: AnyRef): Option[x.type & Symbol] = x match + case sd: SymDenotation => Some(sd.asInstanceOf) + case _ => None + + given ClsTest: TypeTest[AnyRef, ClassSymbol] with + def unapply(x: AnyRef): Option[x.type & ClassSymbol] = x match + case cd: ClassDenotation => Some(cd.asInstanceOf) + case _ => None + end TypeTests + /** A Symbol represents a Scala definition/declaration or a package. * @param coord The coordinates of the symbol (a position or an index) * @param id A unique identifier of the symbol (unique per ContextBase) @@ -84,7 +98,7 @@ object Symbols { type TermSymbol = Symbol { type ThisName = TermName } type TypeSymbol = Symbol { type ThisName = TypeName } - extension (x: AnyRef) + extension (x: Any) inline def isSymbol: Boolean = x.isInstanceOf[Symbol] inline def asSymbol: Symbol = x.asInstanceOf[Symbol] diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 7c25ecd21ebf..f406258f4dbc 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -12,6 +12,7 @@ import Names._ import Flags.{Module, Provisional} import dotty.tools.dotc.config.Config import cc.boxedUnlessFun +import Symbols.TypeTests.given object TypeApplications { @@ -217,7 +218,7 @@ class TypeApplications(val self: Type) extends AnyVal { /** If `self` is a generic class, its type parameter symbols, otherwise Nil */ final def typeParamSymbols(using Context): List[TypeSymbol] = typeParams match { case tparams @ (_: Symbol) :: _ => - assert(tparams.forall(_.isInstanceOf[Symbol])) + assert(tparams.forall(_.isSymbol)) tparams.asInstanceOf[List[TypeSymbol]] // Note: Two successive calls to typeParams can yield different results here because // of different completion status. I.e. the first call might produce some symbols, diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 2a0072590550..2680825996b9 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -24,6 +24,7 @@ import typer.Applications.productSelectorTypes import reporting.trace import annotation.constructorOnly import cc.{CapturingType, derivedCapturingType, CaptureSet, stripCapturing, isBoxedCapturing, boxed, boxedUnlessFun, boxedIfTypeParam, isAlwaysPure} +import Symbols.TypeTests.given /** Provides methods to compare types. */ diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index eba5ff3fc83a..24d29d81f4d4 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -43,6 +43,7 @@ import scala.annotation.internal.sharable import scala.annotation.threadUnsafe import dotty.tools.dotc.transform.SymUtils._ +import Symbols.TypeTests.given object Types { @@ -2719,7 +2720,7 @@ object Types { if (prefix eq this.prefix) this else if !NamedType.validPrefix(prefix) then UnspecifiedErrorType else if (lastDenotation == null) NamedType(prefix, designator) - else designator match { + else (designator: @unchecked) match { // !!! dotty opaque exhaustivity problem case sym: Symbol => if (infoDependsOnPrefix(sym, prefix) && !prefix.isArgPrefixOf(sym)) { val candidate = reload() @@ -2899,7 +2900,7 @@ object Types { } object NamedType { - def isType(desig: Designator)(using Context): Boolean = desig match { + def isType(desig: Designator)(using Context): Boolean = (desig: @unchecked) match { // !!! dotty opaque exhaustivity problem case sym: Symbol => sym.isType case name: Name => name.isTypeName } @@ -5036,7 +5037,7 @@ object Types { TypeAlias( withMode(Mode.CheckCyclic)( LazyRef.of(force)))) - cinfo.selfInfo match + (cinfo.selfInfo: @unchecked) match // !!! dotty opaque exhaustivity problem case self: Type => cinfo.derivedClassInfo( selfInfo = refineSelfType(self.orElse(defn.AnyType))) diff --git a/compiler/src/dotty/tools/dotc/core/Variances.scala b/compiler/src/dotty/tools/dotc/core/Variances.scala index 2401b43c8e17..050d1628b4ea 100644 --- a/compiler/src/dotty/tools/dotc/core/Variances.scala +++ b/compiler/src/dotty/tools/dotc/core/Variances.scala @@ -4,6 +4,7 @@ package core import Types._, Contexts._, Flags._, Symbols._, Annotations._ import TypeApplications.TypeParamInfo import Decorators._ +import Symbols.TypeTests.given object Variances { diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 7702e6a93446..015fb9f55ce6 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -23,6 +23,7 @@ import scala.annotation.switch import typer.Checking.checkNonCyclic import io.{AbstractFile, ZipArchive} import scala.util.control.NonFatal +import Symbols.TypeTests.given object ClassfileParser { /** Marker trait for unpicklers that can be embedded in classfiles. */ diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index bef28545592a..00f8b70fb140 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -19,6 +19,7 @@ import config.Config import collection.mutable import reporting.{Profile, NoProfile} import dotty.tools.tasty.TastyFormat.ASTsSection +import core.Symbols.TypeTests.given object TreePickler: class StackSizeExceeded(val mdef: tpd.MemberDef) extends Exception @@ -212,7 +213,7 @@ class TreePickler(pickler: TastyPickler) { report.error(em"pickling reference to as yet undefined $tpe with symbol ${sym}", sym.srcPos) pickleSymRef(sym) } - else tpe.designator match { + else (tpe.designator: @unchecked) match { // !!! dotty opaque exhaustivity problem case name: Name => writeByte(if (tpe.isType) TYPEREF else TERMREF) pickleName(name); pickleType(tpe.prefix) @@ -598,7 +599,7 @@ class TreePickler(pickler: TastyPickler) { else { if (!tree.self.isEmpty) registerTreeAddr(tree.self) pickleType { - selfInfo match { + (selfInfo: @unchecked) match { // !!! dotty opaque exhaustivity problem case sym: Symbol => sym.info case tp: Type => tp } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 91290b4ddd41..76f119b1a5b5 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -46,6 +46,7 @@ import dotty.tools.tasty.TastyFormat._ import scala.annotation.constructorOnly import scala.annotation.internal.sharable +import Symbols.TypeTests.given /** Unpickler for typed trees * @param reader the reader from which to unpickle diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Erasure.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Erasure.scala index cc2d7dd7ee56..4a5ac0042035 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Erasure.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Erasure.scala @@ -6,6 +6,7 @@ package unpickleScala2 import Symbols._, Types._, Contexts._, Flags._, Names._, StdNames._, Phases._ import Decorators._ import scala.collection.mutable.ListBuffer +import Symbols.TypeTests.given /** Erasure logic specific to Scala 2 symbols. */ object Scala2Erasure: @@ -161,7 +162,7 @@ object Scala2Erasure: * pseudo-symbol, if its upper-bound is a sub of that pseudo-symbol. */ def goUpperBound(psym: Symbol | StructuralRef): Boolean = - val info = psym match + val info = (psym: @unchecked) match // !!! dotty opaque exhaustivity problem case sym: Symbol => sym.info case tp: StructuralRef => tp.info info match @@ -178,7 +179,7 @@ object Scala2Erasure: // is an abstract type upper-bounded by this refinement, since each // textual appearance of a refinement will have its own class symbol. !that.isInstanceOf[Scala2RefinedType] && - psym.match + (psym: @unchecked).match // !!! dotty opaque exhaustivity problem case sym1: Symbol => that match case sym2: Symbol => if sym1.isClass && sym2.isClass then diff --git a/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala b/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala index 86ae99b3e0f9..04c43920aa2e 100644 --- a/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala +++ b/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala @@ -11,6 +11,7 @@ import Denotations.staticRef import NameOps._ import ast.Trees.Tree import Phases.Phase +import Symbols.TypeTests.given /** Load trees from TASTY files */ diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 0da1993310c6..b7fa9c23561e 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -16,6 +16,7 @@ import scala.util.control.NonFatal import scala.annotation.switch import config.{Config, Feature} import cc.{CapturingType, EventuallyCapturingType, CaptureSet, isBoxed} +import Symbols.TypeTests.given class PlainPrinter(_ctx: Context) extends Printer { diff --git a/compiler/src/dotty/tools/dotc/reporting/Message.scala b/compiler/src/dotty/tools/dotc/reporting/Message.scala index a1fe6773c1d2..54c74bb6079c 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Message.scala @@ -12,6 +12,7 @@ import config.SourceVersion import scala.language.unsafeNulls import scala.annotation.threadUnsafe +import Symbols.TypeTests.given /** ## Tips for error message generation * @@ -154,7 +155,7 @@ object Message: /** Produce a where clause with explanations for recorded iterms. */ def explanations(using Context): String = - def needsExplanation(entry: Recorded) = entry match { + def needsExplanation(entry: Recorded) = (entry: @unchecked) match { // !!! dotty opaque exhaustivity problem case param: TypeParamRef => ctx.typerState.constraint.contains(param) case param: ParamRef => false case skolem: SkolemType => true diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index 071efb1fb91c..c39397f238cd 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -24,6 +24,7 @@ import scala.annotation.{ threadUnsafe => tu, tailrec } import scala.PartialFunction.condOpt import dotty.tools.dotc.{semanticdb => s} +import Symbols.TypeTests.given /** Extract symbol references and uses to semanticdb files. * See https://scalameta.org/docs/semanticdb/specification.html#symbol-1 diff --git a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala index a71a07a3f183..0d30f40ca8f2 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala @@ -12,6 +12,7 @@ import core.StdNames.nme import SymbolInformation.{Kind => k} import dotty.tools.dotc.util.SourceFile import dotty.tools.dotc.util.Spans.Span +import core.Symbols.TypeTests.given import java.lang.Character.{isJavaIdentifierPart, isJavaIdentifierStart} @@ -44,7 +45,7 @@ object Scala3: else (span.start, span.end) val nameInSource = content.slice(start, end).mkString // for secondary constructors `this` - desig match + (desig: @unchecked) match // !!! dotty opaque exhaustivity problem case sym: Symbol => if sym.isConstructor && nameInSource == nme.THISkw.toString then true @@ -76,7 +77,7 @@ object Scala3: given SemanticSymbolOps : AnyRef with extension (sym: SemanticSymbol) - def name(using Context): Name = sym match + def name(using Context): Name = (sym: @unchecked) match // !!! dotty opaque exhaustivity problem case s: Symbol => core.Symbols.name(s) case s: WildcardTypeSymbol => nme.WILDCARD case s: TermParamRefSymbol => s.name @@ -84,7 +85,7 @@ object Scala3: case s: RefinementSymbol => s.name def symbolName(using builder: SemanticSymbolBuilder)(using Context): String = - sym match + (sym: @unchecked) match // !!! dotty opaque exhaustivity problem case s: Symbol => builder.symbolName(s) case s: FakeSymbol => s.sname.getOrElse { @@ -94,7 +95,7 @@ object Scala3: } def symbolInfo(symkinds: Set[SymbolKind])(using LinkMode, TypeOps, SemanticSymbolBuilder, Context): SymbolInformation = - sym match + (sym: @unchecked) match // !!! dotty opaque exhaustivity problem case s: Symbol => val kind = s.symbolKind(symkinds) val sname = sym.symbolName diff --git a/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala b/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala index 64ce2ed42282..94107d77c524 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala @@ -12,6 +12,7 @@ import core.StdNames.tpnme import scala.util.chaining.scalaUtilChainingOps import collection.mutable +import core.Symbols.TypeTests.given import dotty.tools.dotc.{semanticdb => s} import Scala3.{FakeSymbol, SemanticSymbol, WildcardTypeSymbol, TypeParamRefSymbol, TermParamRefSymbol, RefinementSymbol} diff --git a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala index 503561915040..41caf4d4efd3 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala @@ -10,6 +10,7 @@ import Symbols._, StdNames._, Trees._ import TypeErasure.ErasedValueType, ValueClasses._ import reporting._ import NameKinds.SuperAccessorName +import Symbols.TypeTests.given object ElimErasedValueType { val name: String = "elimErasedValueType" diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 60affae38ad5..b8b3f97330b3 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -2,39 +2,39 @@ package dotty.tools package dotc package transform -import core.Phases._ -import core.DenotTransformers._ -import core.Denotations._ -import core.SymDenotations._ -import core.Symbols._ -import core.Contexts._ -import core.Types._ -import core.Names._ -import core.StdNames._ -import core.NameOps._ -import core.NameKinds.{AdaptedClosureName, BodyRetainerName, DirectMethName} -import core.Scopes.newScopeWith -import core.Decorators._ -import core.Constants._ -import core.Definitions._ -import core.Annotations.BodyAnnotation +import core.* +import Phases._ +import DenotTransformers._ +import Denotations._ +import SymDenotations._ +import Symbols._ +import Contexts._ +import Types._ +import Names._ +import StdNames._ +import NameOps._ +import NameKinds.{AdaptedClosureName, BodyRetainerName, DirectMethName} +import Scopes.newScopeWith +import Decorators._ +import Constants._ +import Definitions._ +import Annotations.BodyAnnotation import typer.NoChecking import inlines.Inlines import typer.ProtoTypes._ import typer.ErrorReporting.errorTree import typer.Checking.checkValue -import core.TypeErasure._ -import core.Decorators._ +import TypeErasure._ +import Decorators._ import dotty.tools.dotc.ast.{tpd, untpd} import ast.TreeTypeMap -import dotty.tools.dotc.core.{Constants, Flags} import ValueClasses._ import TypeUtils._ import ContextFunctionResults._ import ExplicitOuter._ -import core.Mode import util.Property import reporting._ +import Symbols.TypeTests.given class Erasure extends Phase with DenotTransformer { diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 0552fe31f8a2..4245543a8883 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -9,6 +9,7 @@ import MegaPhase._ import SymUtils._ import NullOpsDecorator._ import ast.untpd +import Symbols.TypeTests.given /** Expand SAM closures that cannot be represented by the JVM as lambdas to anonymous classes. * These fall into five categories diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index cddfe51275c8..bf51633fcf9c 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -3,21 +3,15 @@ package dotc package transform import MegaPhase._ -import core.DenotTransformers._ -import core.Symbols._ -import core.Contexts._ -import core.Phases._ -import core.Types._ -import core.Flags._ -import core.Decorators._ -import core.StdNames.nme -import core.Names._ -import core.NameOps._ -import SymUtils._ +import core.* +import DenotTransformers.*, Symbols.*, Contexts.*, Phases.*, core.Types.*, Flags.* +import Decorators.*, Names.*, NameOps.*, SymUtils.* +import StdNames.nme import dotty.tools.dotc.ast.tpd import collection.mutable import scala.annotation.tailrec +import Symbols.TypeTests.given /** This phase adds outer accessors to classes and traits that need them. * Compared to Scala 2.x, it tries to minimize the set of classes diff --git a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala index a430f7532066..4fdf11fe8ffd 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala @@ -16,6 +16,7 @@ import TypeErasure.{ valueErasure, ErasedValueType } import NameKinds.{ExtMethName, BodyRetainerName} import Decorators._ import TypeUtils._ +import Symbols.TypeTests.given /** * Perform Step 1 in the inline classes SIP: Creates extension methods for all diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala index a7e0795ce195..cb040f81c949 100644 --- a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -18,6 +18,7 @@ import NameKinds.OuterSelectName import StdNames._ import TypeUtils.isErasedValueType import config.Feature +import Symbols.TypeTests.given object FirstTransform { val name: String = "firstTransform" diff --git a/compiler/src/dotty/tools/dotc/transform/ForwardDepChecks.scala b/compiler/src/dotty/tools/dotc/transform/ForwardDepChecks.scala index bf8a6fa6c7bf..fdfc2edcb99e 100644 --- a/compiler/src/dotty/tools/dotc/transform/ForwardDepChecks.scala +++ b/compiler/src/dotty/tools/dotc/transform/ForwardDepChecks.scala @@ -9,6 +9,7 @@ import util.Store import collection.immutable import ast.tpd import MegaPhase.MiniPhase +import Symbols.TypeTests.given object ForwardDepChecks: diff --git a/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala b/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala index a75d6da9dd6a..b972830af420 100644 --- a/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala +++ b/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala @@ -7,6 +7,7 @@ import MegaPhase._ import NameKinds.NonLocalReturnKeyName import config.SourceVersion.* import Decorators.em +import Symbols.TypeTests.given object NonLocalReturns { import ast.tpd._ @@ -90,9 +91,9 @@ class NonLocalReturns extends MiniPhase { } override def transformDefDef(tree: DefDef)(using Context): Tree = - nonLocalReturnKeys.remove(tree.symbol) match - case key: TermSymbol => cpy.DefDef(tree)(rhs = nonLocalReturnTry(tree.rhs, key, tree.symbol)) - case null => tree + val key = nonLocalReturnKeys.remove(tree.symbol) + if key == null then tree + else cpy.DefDef(tree)(rhs = nonLocalReturnTry(tree.rhs, key.asTerm, tree.symbol)) override def transformReturn(tree: Return)(using Context): Tree = if isNonLocalReturn(tree) then diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index f4c4863d073d..99cc5ca783ef 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -373,8 +373,8 @@ class SpaceEngine(using Context) extends SpaceLogic { /** Return the space that represents the pattern `pat` */ def project(pat: Tree): Space = pat match { case Literal(c) => - if (c.value.isInstanceOf[Symbol]) - Typ(c.value.asInstanceOf[Symbol].termRef, decomposed = false) + if (c.value.isSymbol) + Typ(c.value.asSymbol.termRef, decomposed = false) else Typ(ConstantType(c), decomposed = false) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 817fe6f21d24..6bade6d7cb5d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -39,6 +39,7 @@ import config.Feature.sourceVersion import config.SourceVersion._ import printing.Formatting.hlAsKeyword import transform.TypeUtils.* +import Symbols.TypeTests.given import collection.mutable import reporting._ diff --git a/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala b/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala index ef9599be551c..1bb88e8d3023 100644 --- a/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala @@ -9,6 +9,7 @@ import config.{ScalaVersion, NoScalaVersion, Feature, ScalaRelease} import MegaPhase.MiniPhase import scala.util.{Failure, Success} import ast.tpd +import Symbols.TypeTests.given class CrossVersionChecks extends MiniPhase: import tpd.* diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index 0d5b2ce99480..6de575f3c3f6 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -18,6 +18,7 @@ import util.Property import ast.Trees.genericEmptyTree import annotation.{tailrec, constructorOnly} import ast.tpd._ +import Symbols.TypeTests.given /** Synthesize terms for special classes */ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 2ab227593781..32bf95bdaf45 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -51,6 +51,7 @@ import Nullables._ import NullOpsDecorator._ import cc.CheckCaptures import config.Config +import Symbols.TypeTests.given import scala.annotation.constructorOnly From b3c249b1317a4b80565dd8b1fc691ec5e46eece8 Mon Sep 17 00:00:00 2001 From: odersky Date: Fri, 27 Jan 2023 12:44:37 +0100 Subject: [PATCH 13/23] Reorganize maybeOwner --- .../tools/dotc/core/SymDenotations.scala | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 030cb5810a6b..eccb0689364f 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -73,7 +73,7 @@ object SymDenotations { class SymDenotation private[SymDenotations] ( symbolHint: Symbol | Null, final val common: SymCommon, - final val maybeOwner: Symbol, + ownerOrNull: Symbol | Null, final val name: Name, initFlags: FlagSet, initInfo: Type, @@ -91,6 +91,9 @@ object SymDenotations { */ if (Config.checkNoSkolemsInInfo) assertNoSkolems(initInfo) + final def maybeOwner: Symbol = + if ownerOrNull == null then NoSymbol else ownerOrNull + // ------ Getting and setting fields ----------------------------- private var myFlags: FlagSet = adaptFlags(initFlags) @@ -99,7 +102,9 @@ object SymDenotations { private var myParamss: List[List[Symbol]] = Nil /** The owner of the symbol; overridden in NoDenotation */ - def owner: Symbol = maybeOwner + final def owner: Symbol = + assert(ownerOrNull != null, "NoDenotation.owner") + ownerOrNull /** The flag set */ final def flags(using Context): FlagSet = { ensureCompleted(); myFlags } @@ -2057,8 +2062,8 @@ object SymDenotations { val builder = new BaseDataBuilder def traverse(parents: List[Type]): Unit = parents match { case p :: parents1 => - p.classSymbol match { - case pcls: ClassSymbol => builder.addAll(pcls.baseClasses) + p.classSymbol.denot match { + case pcls: ClassDenotation => builder.addAll(pcls.baseClasses) case _ => assert(isRefinementClass || p.isError || ctx.mode.is(Mode.Interactive), s"$this has non-class parent: $p") } traverse(parents1) @@ -2414,8 +2419,8 @@ object SymDenotations { def maybeAdd(name: Name) = if (keepOnly(thisType, name)) names += name try { for ptype <- parentTypes do - ptype.classSymbol match - case pcls: ClassSymbol => + ptype.classSymbol.denot match + case pcls: ClassDenotation => for name <- pcls.memberNames(keepOnly) do maybeAdd(name) val ownSyms = @@ -2678,10 +2683,9 @@ object SymDenotations { } @sharable object NoDenotation - extends SymDenotation(NoSymbol, SymCommon(NoCoord, 0, 0), NoSymbol, "".toTermName, Permanent, NoType) { + extends SymDenotation(NoSymbol, SymCommon(NoCoord, 0, 0), null, "".toTermName, Permanent, NoType) { override def isTerm: Boolean = false override def exists: Boolean = false - override def owner: Symbol = throw new AssertionError("NoDenotation.owner") override def computeAsSeenFrom(pre: Type)(using Context): SingleDenotation = this override def mapInfo(f: Type => Type)(using Context): SingleDenotation = this override def asSeenFrom(pre: Type)(using Context): AsSeenFromResult = this From bc16e2c6836e1d754b57c9ed04f7271d69240582 Mon Sep 17 00:00:00 2001 From: odersky Date: Fri, 27 Jan 2023 13:45:47 +0100 Subject: [PATCH 14/23] Fix rebase breakage --- compiler/src/dotty/tools/dotc/core/GadtConstraint.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/GadtConstraint.scala b/compiler/src/dotty/tools/dotc/core/GadtConstraint.scala index a863a982a44d..45ddb55f74f1 100644 --- a/compiler/src/dotty/tools/dotc/core/GadtConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/GadtConstraint.scala @@ -84,9 +84,9 @@ class GadtConstraint private ( } def externalize(tp: Type, theMap: TypeMap | Null = null)(using Context): Type = tp match - case param: TypeParamRef => reverseMapping(param) match - case sym: Symbol => sym.typeRef - case null => param + case param: TypeParamRef => + val sym = reverseMapping(param) + if sym != null then sym.typeRef else param case tp: TypeAlias => tp.derivedAlias(externalize(tp.alias, theMap)) case tp => (if theMap == null then ExternalizeMap() else theMap).mapOver(tp) From 9aa32de0af3a11a88fbaadc2b6f71196f387f0bb Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 29 Jan 2023 11:17:35 +0100 Subject: [PATCH 15/23] Eliminate toDenot conversions in Symbols They would be skipped when Symbol becomes an opaque type alias, since inside Symbols it is known that Symbol == SymDenotation --- .../src/dotty/tools/dotc/core/Symbols.scala | 57 ++++++++++++++++--- .../src/dotty/tools/dotc/core/Types.scala | 6 +- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index cd080a2d0e9a..f22a365dd7b2 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -20,6 +20,7 @@ import StdNames._ import NameOps._ import transform.SymUtils._ import NameKinds.LazyImplicitName +import Annotations.Annotation import ast.tpd import tpd.{Tree, TreeProvider, TreeOps, EmptyTree, NameTree} import ast.TreeTypeMap @@ -180,6 +181,9 @@ object Symbols { /** The last known denotation of this symbol, without going through `current` */ def lastKnownDenotation: SymDenotation = lastDenot + def classDenot(using Context): ClassDenotation = + _self.denot.asInstanceOf[ClassDenotation] + private[core] def defRunId: RunId = lastDenot.validFor.runId @@ -270,9 +274,9 @@ object Symbols { case owner: ClassSymbol => if owner.is(Package) then d.validFor |= InitialPeriod - if d.is(Module) then d.moduleClass.validFor |= InitialPeriod + if d.is(Module) then d.moduleClass.denot.validFor |= InitialPeriod else - owner.ensureFreshScopeAfter(phase) + owner.classDenot.ensureFreshScopeAfter(phase) assert(isPrivate || phase.changesMembers, i"$_self entered in $owner at undeclared phase $phase") _self.entered case _ => _self @@ -280,8 +284,8 @@ object Symbols { /** Remove symbol from scope of owning class */ final def drop()(using Context): Unit = val d = denot - d.owner.asClass.delete(_self) - if d.is(Module) then d.owner.asClass.delete(d.moduleClass) + d.owner.classDenot.delete(_self) + if d.is(Module) then d.owner.classDenot.delete(d.moduleClass) /** Remove symbol from scope of owning class after given `phase`. Create a fresh * denotation for its owner class if the class does not already have one that starts being valid after `phase`. @@ -293,7 +297,7 @@ object Symbols { else val d = denot assert(!d.owner.is(Package)) - d.owner.asClass.ensureFreshScopeAfter(phase) + d.owner.classDenot.ensureFreshScopeAfter(phase) assert(isPrivate || phase.changesMembers, i"$_self deleted in ${d.owner} at undeclared phase $phase") drop() @@ -365,6 +369,39 @@ object Symbols { else _self + def exists(using Context): Boolean = _self.denot.exists + def owner(using Context): Symbol = _self.denot.owner + def typeParams(using Context): List[TypeSymbol] = _self.denot.typeParams + def thisType(using Context): Type = _self.denot.thisType + def typeRef(using Context): TypeRef = _self.denot.typeRef + def termRef(using Context): TermRef = _self.denot.termRef + def isCompleted(using Context): Boolean = _self.denot.isCompleted + def isCompleting(using Context): Boolean = _self.denot.isCompleting + def ensureCompleted()(using Context): Unit = _self.denot.ensureCompleted() + def unforcedDecls(using Context): Scope = _self.denot.unforcedDecls + def appliedRef(using Context): Type = _self.denot.appliedRef + def namedType(using Context): NamedType = _self.denot.namedType + def unforcedAnnotation(cls: Symbol)(using Context): Option[Annotation] = _self.denot.unforcedAnnotation(cls) + def children(using Context): List[Symbol] = _self.denot.children + def topLevelClass(using Context): Symbol = _self.denot.topLevelClass + def moduleClass(using Context): Symbol = _self.denot.moduleClass + def sourceModule(using Context): Symbol = _self.denot.sourceModule + def underlyingSymbol(using Context): Symbol = _self.denot.underlyingSymbol + def ownersIterator(using Context): Iterator[Symbol] = _self.denot.ownersIterator + def enclosingClass(using Context): Symbol = _self.denot.enclosingClass + def enclosingMethod(using Context): Symbol = _self.denot.enclosingMethod + def typeParamCreationFlags(using Context): FlagSet = _self.denot.typeParamCreationFlags + //def is(flag: Flag)(using Context): Boolean = _self.denot.is(flag) + //def is(flag: Flag, butNot: FlagSet)(using Context): Boolean = _self.denot.is(flag, butNot) + //def isOneOf(fs: FlagSet)(using Context): Boolean = _self.denot.isOneOf(fs) + //def isOneOf(fs: FlagSet, butNot: FlagSet)(using Context): Boolean = _self.denot.isOneOf(fs, butNot) + //def isAllOf(fs: FlagSet)(using Context): Boolean = _self.denot.isAllOf(fs) + //def isAllOf(fs: FlagSet, butNot: FlagSet)(using Context): Boolean = _self.denot.isAllOf(fs, butNot) + // !!! Dotty problem: overloaded extension methods here lead to failures like + // Assertion failed: data race? overwriting method isAllOf with method isAllOf in type TermRef(TermRef(TermRef(ThisType(TypeRef(NoPrefix,module class dotc)),object core),object Symbols),isAllOf), + // |last sym id = 10301, new sym id = 10299, + // |last owner = module class Symbols$, new owner = module class Symbols$, + // SrcPos types and methods // !!! make them use lastDenot? def span: Span = self.span def sourcePos(using Context): SourcePosition = self.sourcePos @@ -411,6 +448,8 @@ object Symbols { def showName(using Context): String = ctx.printer.nameString(_self) def showFullName(using Context): String = ctx.printer.fullNameString(_self) + def debugString: String = self.debugString + end extension type TreeOrProvider = TreeProvider | Tree @@ -474,7 +513,7 @@ object Symbols { def sourceOfClass(using Context): SourceFile = val common = _self.lastKnownDenotation.common.asClass - if !common.source.exists && !_self.denot.is(Package) then + if !common.source.exists && !_self.is(Package) then // this allows sources to be added in annotations after `sourceOfClass` is first called val file = _self.associatedFile if file != null && file.extension != "class" then @@ -491,8 +530,10 @@ object Symbols { } common.source - def classDenot(using Context): ClassDenotation = - _self.denot.asInstanceOf[ClassDenotation] + private def enter(sym: Symbol, scope: Scope = EmptyScope)(using Context): Unit = + _self.classDenot.enter(sym, scope) + + def classInfo(using Context): ClassInfo = _self.classDenot.classInfo end extension diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 24d29d81f4d4..d10ddcb00c39 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2501,6 +2501,7 @@ object Types { s"""data race? overwriting $lastSym with $sym in type $this, |last sym id = ${lastSym.id}, new sym id = ${sym.id}, |last owner = ${lastSym.owner}, new owner = ${sym.owner}, + |last info = ${lastSym.infoOrCompleter}, new info = ${sym.infoOrCompleter} |period = ${ctx.phase} at run ${ctx.runId}""" }) } @@ -2785,7 +2786,10 @@ object Types { override def isOverloaded(using Context): Boolean = denot.isOverloaded def alternatives(using Context): List[TermRef] = - denot.alternatives.map(withDenot(_)) + try denot.alternatives.map(withDenot(_)) + catch case ex: AssertionError => + println(i"error while alts ${denot.alternatives}") + throw ex def altsWith(p: Symbol => Boolean)(using Context): List[TermRef] = denot.altsWith(p).map(withDenot(_)) From 979ee23326bd1f48fb8662efef16548832af7429 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 29 Jan 2023 12:23:32 +0100 Subject: [PATCH 16/23] Rename is... and info extension methods in Symbol There are two separate problems with having `is` and `info` as extension methods in Symnbol. For `is` methods: There's a "data race" error when compiling the compiler with itself. It seems that both of the following conditions must hold for that error to come up: - the extension method must be overloaded - it must have a same-named real method in the target type that is reachable via an implicit conversion. We need to minimize and dig deeper on this one. For `info` the problem is different. We can't have both `info` and `info_=` as extension methods since assignment desugaring does not work for extension methods. We cannot have `info` alone either since then the conversion-based `info =` would not work anymore. We should add a fix that allows assignment desugaring of extension methods to the language; then this problem would go away. --- .../src/dotty/tools/dotc/core/Symbols.scala | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index f22a365dd7b2..79151e3daa74 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -272,7 +272,7 @@ object Symbols { val d = denot d.owner match case owner: ClassSymbol => - if owner.is(Package) then + if owner._is(Package) then d.validFor |= InitialPeriod if d.is(Module) then d.moduleClass.denot.validFor |= InitialPeriod else @@ -296,7 +296,7 @@ object Symbols { atPhase(phase.next)(dropAfter(phase)) else val d = denot - assert(!d.owner.is(Package)) + assert(!d.owner._is(Package)) d.owner.classDenot.ensureFreshScopeAfter(phase) assert(isPrivate || phase.changesMembers, i"$_self deleted in ${d.owner} at undeclared phase $phase") drop() @@ -362,7 +362,7 @@ object Symbols { d.moduleClass.sourceSymbol // The module val always has a zero-extent position else if d.is(Synthetic) then val linked = d.linkedClass - if linked.exists && !linked.is(Synthetic) then linked + if linked.exists && !linked._is(Synthetic) then linked else d.owner.sourceSymbol else if d.isPrimaryConstructor then d.owner.sourceSymbol @@ -375,6 +375,7 @@ object Symbols { def thisType(using Context): Type = _self.denot.thisType def typeRef(using Context): TypeRef = _self.denot.typeRef def termRef(using Context): TermRef = _self.denot.termRef + def _info(using Context): Type = _self.denot.info def isCompleted(using Context): Boolean = _self.denot.isCompleted def isCompleting(using Context): Boolean = _self.denot.isCompleting def ensureCompleted()(using Context): Unit = _self.denot.ensureCompleted() @@ -391,12 +392,12 @@ object Symbols { def enclosingClass(using Context): Symbol = _self.denot.enclosingClass def enclosingMethod(using Context): Symbol = _self.denot.enclosingMethod def typeParamCreationFlags(using Context): FlagSet = _self.denot.typeParamCreationFlags - //def is(flag: Flag)(using Context): Boolean = _self.denot.is(flag) - //def is(flag: Flag, butNot: FlagSet)(using Context): Boolean = _self.denot.is(flag, butNot) - //def isOneOf(fs: FlagSet)(using Context): Boolean = _self.denot.isOneOf(fs) - //def isOneOf(fs: FlagSet, butNot: FlagSet)(using Context): Boolean = _self.denot.isOneOf(fs, butNot) - //def isAllOf(fs: FlagSet)(using Context): Boolean = _self.denot.isAllOf(fs) - //def isAllOf(fs: FlagSet, butNot: FlagSet)(using Context): Boolean = _self.denot.isAllOf(fs, butNot) + def _is(flag: Flag)(using Context): Boolean = _self.denot.is(flag) + def _is(flag: Flag, butNot: FlagSet)(using Context): Boolean = _self.denot.is(flag, butNot) + def _isOneOf(fs: FlagSet)(using Context): Boolean = _self.denot.isOneOf(fs) + def _isOneOf(fs: FlagSet, butNot: FlagSet)(using Context): Boolean = _self.denot.isOneOf(fs, butNot) + def _isAllOf(fs: FlagSet)(using Context): Boolean = _self.denot.isAllOf(fs) + def _isAllOf(fs: FlagSet, butNot: FlagSet)(using Context): Boolean = _self.denot.isAllOf(fs, butNot) // !!! Dotty problem: overloaded extension methods here lead to failures like // Assertion failed: data race? overwriting method isAllOf with method isAllOf in type TermRef(TermRef(TermRef(ThisType(TypeRef(NoPrefix,module class dotc)),object core),object Symbols),isAllOf), // |last sym id = 10301, new sym id = 10299, @@ -513,7 +514,7 @@ object Symbols { def sourceOfClass(using Context): SourceFile = val common = _self.lastKnownDenotation.common.asClass - if !common.source.exists && !_self.is(Package) then + if !common.source.exists && !_self._is(Package) then // this allows sources to be added in annotations after `sourceOfClass` is first called val file = _self.associatedFile if file != null && file.extension != "class" then @@ -664,7 +665,7 @@ object Symbols { owner, name, modFlags | ModuleValCreationFlags, NoCompleter, privateWithin, coord) val modcls = newClassSymbol( owner, modclsName, modclsFlags, infoFn(module, _), privateWithin, coord, assocFile) - module.info = + module.denot.info = if (modcls.isCompleted) TypeRef(owner.thisType, modcls) else new ModuleCompleter(modcls) module @@ -756,7 +757,7 @@ object Symbols { */ def newStubSymbol(owner: Symbol, name: Name, file: AbstractFile | Null = null)(using Context): Symbol = { def stubCompleter = new StubInfo() - val normalizedOwner = if (owner.is(ModuleVal)) owner.moduleClass else owner + val normalizedOwner = if (owner._is(ModuleVal)) owner.moduleClass else owner typr.println(s"creating stub for ${name.show}, owner = ${normalizedOwner.denot.debugString}, file = $file") typr.println(s"decls = ${normalizedOwner.unforcedDecls.toList.map(_.debugString).mkString("\n ")}") // !!! DEBUG //if (base.settings.debug.value) throw new Error() @@ -838,7 +839,7 @@ object Symbols { val tparams = tparamBuf.toList val bounds = boundsFn(trefBuf.toList) for (tparam, bound) <- tparams.lazyZip(bounds) do - tparam.info = bound + tparam.denot.info = bound tparams } @@ -861,7 +862,7 @@ object Symbols { */ def mapSymbols(originals: List[Symbol], ttmap: TreeTypeMap, mapAlways: Boolean = false)(using Context): List[Symbol] = if (originals.forall(sym => - (ttmap.mapType(sym.info) eq sym.info) && + (ttmap.mapType(sym._info) eq sym._info) && !(ttmap.oldOwners contains sym.owner)) && !mapAlways) originals else { @@ -880,7 +881,7 @@ object Symbols { def complete(denot: SymDenotation)(using Context): Unit = - val oinfo = original.info match + val oinfo = original._info match case ClassInfo(pre, _, parents, decls, selfInfo) => assert(original.isClass) val parents1 = parents.mapConserve(ttmap.mapType) @@ -894,7 +895,7 @@ object Symbols { val decls1 = newScope val newTypeParams = mapSymbols(original.typeParams, ttmap1, mapAlways = true) newTypeParams.foreach(decls1.enter) - for sym <- decls do if !sym.is(TypeParam) then decls1.enter(sym) + for sym <- decls do if !sym._is(TypeParam) then decls1.enter(sym) val parents2 = parents1.map(_.substSym(otypeParams, newTypeParams)) val selfInfo1 = selfInfo match case selfInfo: Type => selfInfo.substSym(otypeParams, newTypeParams) @@ -910,10 +911,10 @@ object Symbols { end completer - copy.info = completer + copy.denot.info = completer copy.denot match case cd: ClassDenotation => - cd.registeredCompanion = original.registeredCompanion.subst(originals, copies) + cd.registeredCompanion = original.denot.registeredCompanion.subst(originals, copies) case _ => } @@ -922,9 +923,9 @@ object Symbols { // Update Child annotations of classes encountered previously to new values // if some child is among the mapped symbols for orig <- ttmap1.substFrom do - if orig.is(Sealed) && orig.children.exists(originals.contains) then + if orig._is(Sealed) && orig.children.exists(originals.contains) then val sealedCopy = orig.subst(ttmap1.substFrom, ttmap1.substTo) - sealedCopy.annotations = sealedCopy.annotations.mapConserve(ttmap1.apply) + sealedCopy.denot.annotations = sealedCopy.denot.annotations.mapConserve(ttmap1.apply) copies } @@ -949,7 +950,7 @@ object Symbols { def requiredPackage(path: PreName)(using Context): TermSymbol = { val name = path.toTermName - staticRef(name, isPackage = true).requiredSymbol("package", name)(_.is(Package)).asTerm + staticRef(name, isPackage = true).requiredSymbol("package", name)(_._is(Package)).asTerm } def requiredPackageRef(path: PreName)(using Context): TermRef = requiredPackage(path).termRef @@ -982,11 +983,11 @@ object Symbols { */ def getPackageClassIfDefined(path: PreName)(using Context): Symbol = staticRef(path.toTypeName, isPackage = true, generateStubs = false) - .disambiguate(_ is PackageClass).symbol + .disambiguate(_._is(PackageClass)).symbol def requiredModule(path: PreName)(using Context): TermSymbol = { val name = path.toTermName - staticRef(name).requiredSymbol("object", name)(_.is(Module)).asTerm + staticRef(name).requiredSymbol("object", name)(_._is(Module)).asTerm } /** Get module symbol if the module is either defined in current compilation run @@ -994,13 +995,13 @@ object Symbols { */ def getModuleIfDefined(path: PreName)(using Context): Symbol = staticRef(path.toTermName, generateStubs = false) - .disambiguate(_.is(Module)).symbol + .disambiguate(_._is(Module)).symbol def requiredModuleRef(path: PreName)(using Context): TermRef = requiredModule(path).termRef def requiredMethod(path: PreName)(using Context): TermSymbol = { val name = path.toTermName - staticRef(name).requiredSymbol("method", name)(_.is(Method)).asTerm + staticRef(name).requiredSymbol("method", name)(_._is(Method)).asTerm } def requiredMethodRef(path: PreName)(using Context): TermRef = requiredMethod(path).termRef From 636db78c75b67326abcfcbf8e879c5f2204c584d Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 29 Jan 2023 13:11:54 +0100 Subject: [PATCH 17/23] Disallow use of toDenot and toClassDenot conversions in Symbols We can't allow them in symbols since they would not kick in when Symbol and ClassSymbol are made opaque type aliases, because inside Symbols we know that these types are aliases of Denotations so no conversion would be applied then and we would possibly end up with a denotation at the wrong validity period. --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- compiler/src/dotty/tools/dotc/core/Symbols.scala | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index eccb0689364f..976086780a95 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1600,7 +1600,7 @@ object SymDenotations { // ----- Sanity checks and debugging */ - def debugString: String = toString + "#" + symbol.id // !!! DEBUG + def debugString: String = toString + "#" + common.id // !!! DEBUG def hasSkolems(tp: Type): Boolean = tp match { case tp: SkolemType => true diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 79151e3daa74..3dd798bb3ba4 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -555,6 +555,12 @@ object Symbols { /** Makes all class denotation operations available on class symbols */ implicit def toClassDenot(cls: ClassSymbol)(using Context): ClassDenotation = cls.classDenot + /** Blocks use of `toDenot` conversion in Symbols itself */ + private implicit def toDenotALT(sym: Symbol)(using Context): SymDenotation = sym.denot + + /** Blocks use of `toClassDenot` conversion in Symbols itself */ + private implicit def toClassDenotALT(cls: ClassSymbol)(using Context): ClassDenotation = cls.classDenot + /** The Definitions object */ def defn(using Context): Definitions = ctx.definitions From f3b15ed5537dae8e92440bc68afd7a10d556379b Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 29 Jan 2023 14:04:55 +0100 Subject: [PATCH 18/23] Change Symbol.exists to not use denot --- compiler/src/dotty/tools/dotc/core/Symbols.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 3dd798bb3ba4..d7265d5068e3 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -369,7 +369,7 @@ object Symbols { else _self - def exists(using Context): Boolean = _self.denot.exists + def exists(using Context): Boolean = _self ne NoSymbol def owner(using Context): Symbol = _self.denot.owner def typeParams(using Context): List[TypeSymbol] = _self.denot.typeParams def thisType(using Context): Type = _self.denot.thisType From 08308625b30f13b18dc27fa541dc1994c0c51f5f Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 29 Jan 2023 16:43:18 +0100 Subject: [PATCH 19/23] Drop private enter extension method --- compiler/src/dotty/tools/dotc/core/Symbols.scala | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index d7265d5068e3..91709c0a80b4 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -255,8 +255,8 @@ object Symbols { final def entered(using Context): _self.type = val d = denot if d.owner.isClass then - d.owner.asClass.enter(_self) - if d.is(Module) then d.owner.asClass.enter(d.moduleClass) + d.owner.classDenot.enter(_self) + if d.is(Module) then d.owner.classDenot.enter(d.moduleClass) _self @@ -531,9 +531,6 @@ object Symbols { } common.source - private def enter(sym: Symbol, scope: Scope = EmptyScope)(using Context): Unit = - _self.classDenot.enter(sym, scope) - def classInfo(using Context): ClassInfo = _self.classDenot.classInfo end extension From 7a787d6e828b9941b31e8878056b2f5981c869e6 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 29 Jan 2023 17:51:46 +0100 Subject: [PATCH 20/23] Make Symbol accesses null-safe --- .../tools/backend/jvm/BCodeBodyBuilder.scala | 22 ++++++------ .../tools/backend/jvm/BCodeSkelBuilder.scala | 6 ++-- .../tools/backend/jvm/BCodeSyncAndTry.scala | 18 +++++----- .../dotty/tools/backend/sjs/JSCodeGen.scala | 34 +++++++++---------- .../tools/backend/sjs/JSExportsGen.scala | 8 ++--- .../src/dotty/tools/dotc/core/Contexts.scala | 3 +- .../dotty/tools/dotc/core/Denotations.scala | 3 +- .../tools/dotc/core/GadtConstraint.scala | 4 +-- .../tools/dotc/core/SymDenotations.scala | 6 ++-- .../src/dotty/tools/dotc/core/Types.scala | 8 ++--- .../dotc/core/classfile/ClassfileParser.scala | 3 +- .../core/unpickleScala2/Scala2Erasure.scala | 2 +- .../core/unpickleScala2/Scala2Unpickler.scala | 10 +++--- .../dotc/transform/NonLocalReturns.scala | 4 +-- 14 files changed, 67 insertions(+), 64 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala index 989a05a0784e..3e6d942f39a2 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala @@ -521,20 +521,20 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { /* * must-single-thread */ - def fieldLoad( field: Symbol, hostClass: Symbol = null): Unit = fieldOp(field, isLoad = true, hostClass) + def fieldLoad( field: Symbol, hostClass: Symbol | Null = null): Unit = fieldOp(field, isLoad = true, hostClass) /* * must-single-thread */ - def fieldStore(field: Symbol, hostClass: Symbol = null): Unit = fieldOp(field, isLoad = false, hostClass) + def fieldStore(field: Symbol, hostClass: Symbol | Null = null): Unit = fieldOp(field, isLoad = false, hostClass) /* * must-single-thread */ - private def fieldOp(field: Symbol, isLoad: Boolean, specificReceiver: Symbol): Unit = { + private def fieldOp(field: Symbol, isLoad: Boolean, specificReceiver: Symbol | Null): Unit = { val useSpecificReceiver = specificReceiver != null && !field.isScalaStatic - val owner = internalName(if (useSpecificReceiver) specificReceiver else field.owner) + val owner = internalName(if (useSpecificReceiver) specificReceiver.nn else field.owner) val fieldJName = field.javaSimpleName val fieldDescr = symInfoTK(field).descriptor val isStatic = field.isStaticMember @@ -629,7 +629,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { if (earlyReturnVar == null) { earlyReturnVar = locals.makeLocal(returnType, "earlyReturnVar", expr.tpe, expr.span) } - locals.store(earlyReturnVar) + locals.store(earlyReturnVar.nn) } bc goTo nextCleanup shouldEmitCleanup = true @@ -853,7 +853,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { bc.invokevirtual(target, sym.javaSimpleName, methodBType.descriptor) generatedType = methodBType.returnType } else { - val receiverClass = if (!invokeStyle.isVirtual) null else { + val receiverClass: Symbol | Null = if (!invokeStyle.isVirtual) null else { // receiverClass is used in the bytecode to as the method receiver. using sym.owner // may lead to IllegalAccessErrors, see 9954eaf / aladdin bug 455. val qualSym = qual.tpe.typeSymbol @@ -1389,16 +1389,16 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { * invocation instruction, otherwise `method.owner`. A specific receiver class is needed to * prevent an IllegalAccessError, (aladdin bug 455). */ - def genCallMethod(method: Symbol, style: InvokeStyle, pos: Span = NoSpan, specificReceiver: Symbol = null): BType = { + def genCallMethod(method: Symbol, style: InvokeStyle, pos: Span = NoSpan, specificReceiver: Symbol | Null = null): BType = { val methodOwner = method.owner // the class used in the invocation's method descriptor in the classfile - val receiverClass = { + val receiverClass: Symbol = { if (specificReceiver != null) assert(style.isVirtual || specificReceiver == methodOwner, s"specificReceiver can only be specified for virtual calls. $method - $specificReceiver") - val useSpecificReceiver = specificReceiver != null && !defn.isBottomClass(specificReceiver) && !method.isScalaStatic - val receiver = if (useSpecificReceiver) specificReceiver else methodOwner + val useSpecificReceiver = specificReceiver != null && !defn.isBottomClass(specificReceiver.nn) && !method.isScalaStatic + val receiver = if (useSpecificReceiver) specificReceiver.nn else methodOwner // workaround for a JVM bug: https://bugs.openjdk.java.net/browse/JDK-8154587 // when an interface method overrides a member of Object (note that all interfaces implicitly @@ -1432,7 +1432,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { val bmType = asmMethodType(method) val mdescr = bmType.descriptor - val isInterface = isEmittedInterface(receiverClass) + val isInterface = isEmittedInterface(receiverClass.nn) import InvokeStyle._ if (style == Super) { if (isInterface && !method.is(JavaDefined)) { diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala index 1885210a6687..3ace8df6ea42 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala @@ -87,7 +87,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { var cnode: ClassNode1 = null var thisName: String = null // the internal name of the class being emitted - var claszSymbol: Symbol = null + var claszSymbol: Symbol = _ var isCZParcelable = false var isCZStaticModule = false @@ -364,9 +364,9 @@ trait BCodeSkelBuilder extends BCodeHelpers { var jMethodName: String = null var isMethSymStaticCtor = false var returnType: BType = null - var methSymbol: Symbol = null + var methSymbol: Symbol = _ // used by genLoadTry() and genSynchronized() - var earlyReturnVar: Symbol = null + var earlyReturnVar: Symbol | Null = null var shouldEmitCleanup = false // stack tracking var stackHeight = 0 diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeSyncAndTry.scala b/compiler/src/dotty/tools/backend/jvm/BCodeSyncAndTry.scala index b5ed27511e7e..d54d6f4572f4 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeSyncAndTry.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeSyncAndTry.scala @@ -36,7 +36,7 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder { // if the synchronized block returns a result, store it in a local variable. // Just leaving it on the stack is not valid in MSIL (stack is cleaned when leaving try-blocks). val hasResult = (expectedType != UNIT) - val monitorResult: Symbol = if (hasResult) locals.makeLocal(tpeTK(args.head), "monitorResult", defn.ObjectType, tree.span) else null + val monitorResult: Symbol | Null = if (hasResult) locals.makeLocal(tpeTK(args.head), "monitorResult", defn.ObjectType, tree.span) else null /* ------ (1) pushing and entering the monitor, also keeping a reference to it in a local var. ------ */ genLoadQualifier(fun) @@ -55,7 +55,7 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder { registerCleanup(monCleanup) genLoad(args.head, expectedType /* toTypeKind(tree.tpe.resultType) */) unregisterCleanup(monCleanup) - if (hasResult) { locals.store(monitorResult) } + if (hasResult) { locals.store(monitorResult.nn) } nopIfNeeded(startProtected) val endProtected = currProgramPoint() @@ -66,7 +66,7 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder { */ locals.load(monitor) emit(asm.Opcodes.MONITOREXIT) - if (hasResult) { locals.load(monitorResult) } + if (hasResult) { locals.load(monitorResult.uncheckedNN) } val postHandler = new asm.Label bc goTo postHandler @@ -214,7 +214,7 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder { * please notice `tmp` has type tree.tpe, while `earlyReturnVar` has the method return type. * Because those two types can be different, dedicated vars are needed. */ - val tmp = if (guardResult) locals.makeLocal(tpeTK(tree), "tmp", tree.tpe, tree.span) else null + val tmp: Symbol | Null = if (guardResult) locals.makeLocal(tpeTK(tree), "tmp", tree.tpe, tree.span) else null /* * upon early return from the try-body or one of its EHs (but not the EH-version of the finally-clause) @@ -375,8 +375,8 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder { cleanups match { case Nil => if (earlyReturnVar != null) { - locals.load(earlyReturnVar) - bc.emitRETURN(locals(earlyReturnVar).tk) + locals.load(earlyReturnVar.uncheckedNN) + bc.emitRETURN(locals(earlyReturnVar.uncheckedNN).tk) } else { bc emitRETURN UNIT } @@ -396,15 +396,15 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder { } /* `tmp` (if non-null) is the symbol of the local-var used to preserve the result of the try-body, see `guardResult` */ - def emitFinalizer(finalizer: Tree, tmp: Symbol, isDuplicate: Boolean): Unit = { + def emitFinalizer(finalizer: Tree, tmp: Symbol | Null, isDuplicate: Boolean): Unit = { var saved: immutable.Map[ /* Labeled */ Symbol, (BType, LoadDestination) ] = null if (isDuplicate) { saved = jumpDest } // when duplicating, the above guarantees new asm.Labels are used for LabelDefs contained in the finalizer (their vars are reused, that's ok) - if (tmp != null) { locals.store(tmp) } + if (tmp != null) { locals.store(tmp.uncheckedNN) } genLoad(finalizer, UNIT) - if (tmp != null) { locals.load(tmp) } + if (tmp != null) { locals.load(tmp.uncheckedNN) } if (isDuplicate) { jumpDest = saved } diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 4caf1f6b5fa2..96b63392c1a2 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -72,8 +72,8 @@ class JSCodeGen()(using genCtx: Context) { private val generatedClasses = mutable.ListBuffer.empty[js.ClassDef] private val generatedStaticForwarderClasses = mutable.ListBuffer.empty[(Symbol, js.ClassDef)] - val currentClassSym = new ScopedVar[Symbol] - private val currentMethodSym = new ScopedVar[Symbol] + val currentClassSym = new ScopedVar[Symbol | Null] + private val currentMethodSym = new ScopedVar[Symbol | Null] private val localNames = new ScopedVar[LocalNameGenerator] private val thisLocalVarIdent = new ScopedVar[Option[js.LocalIdent]] private val isModuleInitialized = new ScopedVar[ScopedVar.VarBox[Boolean]] @@ -126,7 +126,7 @@ class JSCodeGen()(using genCtx: Context) { implicit def implicitLocalNames: LocalNameGenerator = localNames.get def currentThisType: jstpe.Type = { - encodeClassType(currentClassSym) match { + encodeClassType(currentClassSym.get.nn) match { case tpe @ jstpe.ClassType(cls) => jstpe.BoxedClassToPrimType.getOrElse(cls, tpe) case tpe => @@ -856,7 +856,7 @@ class JSCodeGen()(using genCtx: Context) { /** Gen definitions for the fields of a class. */ private def genClassFields(td: TypeDef): List[js.MemberDef] = { val classSym = td.symbol.asClass - assert(currentClassSym.get == classSym, + assert(currentClassSym.get eq classSym, "genClassFields called with a ClassDef other than the current one") val isJSClass = classSym.isNonNativeJSClass @@ -1493,7 +1493,7 @@ class JSCodeGen()(using genCtx: Context) { if (primitives.isPrimitive(sym)) { None - } else if (sym.is(Deferred) && currentClassSym.isNonNativeJSClass) { + } else if (sym.is(Deferred) && currentClassSym.get.nn.isNonNativeJSClass) { // scala-js/#4409: Do not emit abstract methods in non-native JS classes None } else if (sym.is(Deferred)) { @@ -1503,7 +1503,7 @@ class JSCodeGen()(using genCtx: Context) { } else if (isIgnorableDefaultParam) { // #11592 None - } else if (sym.is(Bridge) && sym.name.is(DefaultGetterName) && currentClassSym.isNonNativeJSClass) { + } else if (sym.is(Bridge) && sym.name.is(DefaultGetterName) && currentClassSym.get.nn.isNonNativeJSClass) { /* #12572 Bridges for default accessors in non-native JS classes must not be emitted, * because they call another default accessor, making their entire body an * that cannot be eliminated. @@ -1582,7 +1582,7 @@ class JSCodeGen()(using genCtx: Context) { else genExpr(tree) } - if (namespace.isStatic || !currentClassSym.isNonNativeJSClass) { + if (namespace.isStatic || !currentClassSym.get.nn.isNonNativeJSClass) { val flags = js.MemberFlags.empty.withNamespace(namespace) js.MethodDef(flags, methodName, originalName, jsParams, resultIRType, Some(genBody()))( optimizerHints, None) @@ -1688,7 +1688,7 @@ class JSCodeGen()(using genCtx: Context) { tree match { case _: This => val sym = tree.symbol - if (sym != currentClassSym.get && sym.is(Module)) + if ((sym ne currentClassSym.get) && sym.is(Module)) genLoadModuleOrGlobalScope(sym) else MaybeGlobalScope.NotGlobalScope(genExpr(tree)) @@ -1784,7 +1784,7 @@ class JSCodeGen()(using genCtx: Context) { genApplyDynamic(app)*/ case tree: This => - val currentClass = currentClassSym.get + val currentClass = currentClassSym.get.nn val symIsModuleClass = tree.symbol.is(ModuleClass) assert(tree.symbol == currentClass || symIsModuleClass, s"Trying to access the this of another class: tree.symbol = ${tree.symbol}, class symbol = $currentClass") @@ -1886,8 +1886,8 @@ class JSCodeGen()(using genCtx: Context) { val qualifier = lhs.qualifier def ctorAssignment = ( - currentMethodSym.get.name == nme.CONSTRUCTOR && - currentMethodSym.get.owner == qualifier.symbol && + currentMethodSym.get.nn.name == nme.CONSTRUCTOR && + currentMethodSym.get.nn.owner == qualifier.symbol && qualifier.isInstanceOf[This] ) // TODO This fails for OFFSET$x fields. Re-enable when we can. @@ -2178,7 +2178,7 @@ class JSCodeGen()(using genCtx: Context) { if (sym == defn.Any_getClass) { // The only primitive that is also callable as super call js.GetClass(genThis()) - } else if (currentClassSym.isNonNativeJSClass) { + } else if (currentClassSym.get.nn.isNonNativeJSClass) { genJSSuperCall(tree, isStat) } else { /* #3013 `qual` can be `this.$outer()` in some cases since Scala 2.12, @@ -2188,10 +2188,10 @@ class JSCodeGen()(using genCtx: Context) { genExpr(qual), sym, genActualArgs(sym, args)) // Initialize the module instance just after the super constructor call. - if (isStaticModule(currentClassSym) && !isModuleInitialized.get.value && - currentMethodSym.get.isClassConstructor) { + if (isStaticModule(currentClassSym.get.nn) && !isModuleInitialized.get.value && + currentMethodSym.get.nn.isClassConstructor) { isModuleInitialized.get.value = true - val className = encodeClassName(currentClassSym) + val className = encodeClassName(currentClassSym.get.nn) val thisType = jstpe.ClassType(className) val initModule = js.StoreModule(className, js.This()(thisType)) js.Block(superCall, initModule) @@ -3245,7 +3245,7 @@ class JSCodeGen()(using genCtx: Context) { genApplyJSClassMethod(genReceiver, sym, genScalaArgs) } else { val jsSuperClassValue = explicitJSSuperClassValue.orElse { - Some(genLoadJSConstructor(currentClassSym.get.asClass.superClass)) + Some(genLoadJSConstructor(currentClassSym.get.nn.asClass.superClass)) } genApplyJSMethodGeneric(sym, MaybeGlobalScope.NotGlobalScope(genReceiver), genJSArgs, isStat, jsSuperClassValue)(tree.sourcePos) @@ -3873,7 +3873,7 @@ class JSCodeGen()(using genCtx: Context) { case JS_NEW_TARGET => // js.new.target - val valid = currentMethodSym.get.isClassConstructor && currentClassSym.isNonNativeJSClass + val valid = currentMethodSym.get.nn.isClassConstructor && currentClassSym.get.nn.isNonNativeJSClass if (!valid) { report.error( "Illegal use of js.`new`.target.\n" + diff --git a/compiler/src/dotty/tools/backend/sjs/JSExportsGen.scala b/compiler/src/dotty/tools/backend/sjs/JSExportsGen.scala index 78412999bb34..4182b5770d02 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSExportsGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSExportsGen.scala @@ -585,7 +585,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) { } private def reportCannotDisambiguateError(jsName: JSName, alts: List[Symbol]): Unit = { - val currentClass = currentClassSym.get + val currentClass = currentClassSym.get.nn /* Find a position that is in the current class for decent error reporting. * If there are more than one, always use the "highest" one (i.e., the @@ -623,7 +623,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) { */ private def genApplyForSingleExported(formalArgsRegistry: FormalArgsRegistry, exported: Exported, static: Boolean): js.Tree = { - if (currentClassSym.isJSType && exported.sym.owner != currentClassSym.get) { + if (currentClassSym.get.nn.isJSType && exported.sym.owner != currentClassSym.get) { assert(!static, s"nonsensical JS super call in static export of ${exported.sym}") genApplyForSingleExportedJSSuperCall(formalArgsRegistry, exported) } else { @@ -642,7 +642,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) { val allArgs = formalArgsRegistry.genAllArgsRefsForForwarder() val superClass = { - val superClassSym = currentClassSym.asClass.superClass + val superClassSym = currentClassSym.get.nn.asClass.superClass if (superClassSym.isNestedJSClass) js.VarRef(js.LocalIdent(JSSuperClassParamName))(jstpe.AnyType) else @@ -806,7 +806,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) { implicit pos: SourcePosition): js.Tree = { val sym = exported.sym - val currentClass = currentClassSym.get + val currentClass = currentClassSym.get.nn def receiver = if (static) genLoadModule(sym.owner) diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 2f28975dd066..5947c7dd5707 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -226,7 +226,8 @@ object Contexts { */ def effectiveScope(using Context): Scope = val myOwner: Symbol | Null = owner - if myOwner != null && myOwner.isClass then myOwner.asClass.unforcedDecls + if myOwner != null && myOwner.uncheckedNN.isClass + then myOwner.uncheckedNN.asClass.unforcedDecls else scope def nestingLevel: Int = effectiveScope.nestingLevel diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 179c70663f60..997d7df00580 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -184,8 +184,7 @@ object Denotations { type AsSeenFromResult <: Denotation val symbol: Symbol = - if symbolHint != null then symbolHint - else this.asInstanceOf[Symbol] + (if symbolHint != null then symbolHint else this).asInstanceOf[Symbol] /** The type info. * The info is an instance of TypeType iff this is a type denotation diff --git a/compiler/src/dotty/tools/dotc/core/GadtConstraint.scala b/compiler/src/dotty/tools/dotc/core/GadtConstraint.scala index 45ddb55f74f1..082d634113b4 100644 --- a/compiler/src/dotty/tools/dotc/core/GadtConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/GadtConstraint.scala @@ -85,8 +85,8 @@ class GadtConstraint private ( def externalize(tp: Type, theMap: TypeMap | Null = null)(using Context): Type = tp match case param: TypeParamRef => - val sym = reverseMapping(param) - if sym != null then sym.typeRef else param + val sym: Symbol | Null = reverseMapping(param) + if sym != null then sym.uncheckedNN.typeRef else param case tp: TypeAlias => tp.derivedAlias(externalize(tp.alias, theMap)) case tp => (if theMap == null then ExternalizeMap() else theMap).mapOver(tp) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 976086780a95..819ecce60cfe 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -92,7 +92,7 @@ object SymDenotations { if (Config.checkNoSkolemsInInfo) assertNoSkolems(initInfo) final def maybeOwner: Symbol = - if ownerOrNull == null then NoSymbol else ownerOrNull + if ownerOrNull == null then NoSymbol else ownerOrNull.asInstanceOf[Symbol] // ------ Getting and setting fields ----------------------------- @@ -104,7 +104,7 @@ object SymDenotations { /** The owner of the symbol; overridden in NoDenotation */ final def owner: Symbol = assert(ownerOrNull != null, "NoDenotation.owner") - ownerOrNull + ownerOrNull.asInstanceOf[Symbol] /** The flag set */ final def flags(using Context): FlagSet = { ensureCompleted(); myFlags } @@ -1648,7 +1648,7 @@ object SymDenotations { val privateWithin1 = if (privateWithin != null) privateWithin else this.privateWithin val annotations1 = if (annotations != null) annotations else this.annotations val rawParamss1 = if rawParamss != null then rawParamss else this.rawParamss - val d = SymDenotation(symbol, symbol.lastKnownDenotation.common, owner, name, initFlags1, info1, privateWithin1) + val d = SymDenotation(symbol, symbol.lastKnownDenotation.common, owner, name, initFlags1, info1, privateWithin1.uncheckedNN) d.annotations = annotations1 d.rawParamss = rawParamss1 d.registeredCompanion = registeredCompanion diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index d10ddcb00c39..6bd706802e4b 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2342,7 +2342,7 @@ object Types { def fromDesignator = designator match { case name: Name => val sym = lastSymbol - val allowPrivate = sym == null || (sym == NoSymbol) || sym.lastKnownDenotation.flagsUNSAFE.is(Private) + val allowPrivate = (sym == null) || (sym eq NoSymbol) || sym.asInstanceOf[Symbol].lastKnownDenotation.flagsUNSAFE.is(Private) finish(memberDenot(name, allowPrivate)) case desig => val sym = desig.asSymbol @@ -2469,9 +2469,9 @@ object Types { private def checkSymAssign(sym: Symbol)(using Context) = { def selfTypeOf(sym: Symbol) = if (sym.isClass) sym.asClass.givenSelfType else NoType - val lastSym = lastSymbol + val lastSym: Symbol = lastSymbol.asInstanceOf[Symbol] assert( - (lastSym == null) + (lastSym eq null) || (lastSym eq sym) || @@ -2494,7 +2494,7 @@ object Types { ) || sym == defn.AnyClass.primaryConstructor, { - if lastSym == null then + if lastSym eq null then s"""data race? overwriting $lastSym with $sym in type $this, |period = ${ctx.phase} at run ${ctx.runId}""" else diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 015fb9f55ce6..7fb53b48037b 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -365,7 +365,8 @@ class ClassfileParser( ct.convertTo(pt) } - private def sigToType(sig: String, owner: Symbol = null, isVarargs: Boolean = false)(using Context): Type = { + private def sigToType(sig: String, ownerOrNull: Symbol | Null = null, isVarargs: Boolean = false)(using Context): Type = { + def owner = ownerOrNull.asInstanceOf[Symbol] var index = 0 val end = sig.length def accept(ch: Char): Unit = { diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Erasure.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Erasure.scala index 4a5ac0042035..005c4faf7350 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Erasure.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Erasure.scala @@ -123,7 +123,7 @@ object Scala2Erasure: */ def isClass: Boolean = psym match case sym: Symbol => - sym.isClass + Symbols.isClass(sym) case _: Scala2RefinedType => true case _ => diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 50b0b875c1fc..45db19be5eee 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -1074,24 +1074,26 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas // Set by the three functions to follow. If symbol is non-null // after the new tree 't' has been created, t has its Symbol // set to symbol; and it always has its Type set to tpe. - var symbol: Symbol = null + var mySymbol: Symbol | Null = null var mods: Modifiers = null var name: Name = null + def symbol = mySymbol.nn + /** Read a Symbol, Modifiers, and a Name */ def setSymModsName(): Unit = { - symbol = readSymbolRef() + mySymbol = readSymbolRef() mods = readModifiersRef(symbol.isType) name = readNameRef() } /** Read a Symbol and a Name */ def setSymName(): Unit = { - symbol = readSymbolRef() + mySymbol = readSymbolRef() name = readNameRef() } /** Read a Symbol */ def setSym(): Unit = - symbol = readSymbolRef() + mySymbol = readSymbolRef() implicit val span: Span = NoSpan diff --git a/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala b/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala index b972830af420..f7c4afda75d3 100644 --- a/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala +++ b/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala @@ -91,9 +91,9 @@ class NonLocalReturns extends MiniPhase { } override def transformDefDef(tree: DefDef)(using Context): Tree = - val key = nonLocalReturnKeys.remove(tree.symbol) + val key: Symbol | Null = nonLocalReturnKeys.remove(tree.symbol) if key == null then tree - else cpy.DefDef(tree)(rhs = nonLocalReturnTry(tree.rhs, key.asTerm, tree.symbol)) + else cpy.DefDef(tree)(rhs = nonLocalReturnTry(tree.rhs, key.nn.asTerm, tree.symbol)) override def transformReturn(tree: Return)(using Context): Tree = if isNonLocalReturn(tree) then From 129b6da93c08d6ea12b822ede463fee934619767 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 29 Jan 2023 19:32:08 +0100 Subject: [PATCH 21/23] Make Symbol and ClassSymbol opaque type aliases --- .../dotty/tools/dotc/core/Denotations.scala | 5 +- .../src/dotty/tools/dotc/core/Periods.scala | 9 ++- .../tools/dotc/core/SymDenotations.scala | 4 +- .../src/dotty/tools/dotc/core/Symbols.scala | 70 +++++++------------ .../SnippetCompilerDataCollector.scala | 1 + 5 files changed, 36 insertions(+), 53 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 997d7df00580..19349f60eee4 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -235,11 +235,8 @@ object Denotations { private var myValidFor: Period = Nowhere final def validFor: Period = myValidFor - final def validFor_=(p: Period): Unit = { + final def validFor_=(p: Period): Unit = myValidFor = p - if symbol.initialDenot ne null then - symbol.initialDenot.checkedPeriod = Nowhere - } /** Is this denotation different from NoDenotation or an ErrorDenotation? */ def exists: Boolean = true diff --git a/compiler/src/dotty/tools/dotc/core/Periods.scala b/compiler/src/dotty/tools/dotc/core/Periods.scala index ee877fb538d4..e7aa5ee31c87 100644 --- a/compiler/src/dotty/tools/dotc/core/Periods.scala +++ b/compiler/src/dotty/tools/dotc/core/Periods.scala @@ -63,7 +63,7 @@ object Periods { // // Let's compute: // - // lastDiff = X * 2^5 + (l1 - l2) mod 2^5 + // lastDiff = X * 2^7 + (l1 - l2) mod 2^7 // where X >= 0, X == 0 iff r1 == r2 & l1 - l2 >= 0 // result = lastDiff + d2 <= d1 // We have: @@ -103,6 +103,13 @@ object Periods { def !=(that: Period): Boolean = this.code != that.code } + /** Same as new Period(p1).contains(new Period(p2)), assuming that p2 is the + * code of a single-phase period. + */ + extension (p1: Int) + transparent inline def containsSinglePhasePeriod(p2: Int): Boolean = + ((p1 - p2) >>> PhaseWidth) <= (p1 & PhaseMask) + object Period { /** The single-phase period consisting of given run id and phase id */ diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 819ecce60cfe..1d19947a145a 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -80,7 +80,7 @@ object SymDenotations { initPrivateWithin: Symbol = NoSymbol) extends SingleDenotation(symbolHint, initInfo, name.isTypeName), ParamInfo, SrcPos, Named { - //assert(symbol.id != 4940, name) + //assert(common.id != 9141, name) override def hasUniqueSym: Boolean = exists @@ -1810,7 +1810,6 @@ object SymDenotations { /** The last denotation of this symbol */ var lastDenot: SymDenotation = _ - var checkedPeriod: Period = Nowhere /** Overridden in NoSymbol */ //private[SymDenotations] @@ -2699,7 +2698,6 @@ object SymDenotations { override def filterWithFlags(required: FlagSet, excluded: FlagSet)(using Context): SingleDenotation = this override def associatedFile(using Context): AbstractFile | Null = NoSource.file - NoSymbol.initialDenot = this NoSymbol.denot_=(this) validFor = Period.allInRun(NoRunId) } diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 91709c0a80b4..97e15847db79 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -37,34 +37,32 @@ import scala.reflect.TypeTest object Symbols { - implicit def eqSymbol: CanEqual[Symbol, Symbol] = CanEqual.derived - /** Tree attachment containing the identifiers in a tree as a sorted array */ val Ids: Property.Key[Array[String]] = new Property.Key - opaque type Symbl <: ParamInfo & SrcPos & Named & printing.Showable + opaque type Symbol <: ParamInfo & SrcPos & Named & printing.Showable = SymDenotation - - opaque type ClassSymbl <: Symbl + opaque type ClassSymbol <: TypeSymbol = ClassDenotation object TypeTests: - given SymTest: TypeTest[AnyRef, Symbol] with - def unapply(x: AnyRef): Option[x.type & Symbol] = x match - case sd: SymDenotation => Some(sd.asInstanceOf) + given SymTest: TypeTest[Any, Symbol] with + def unapply(x: Any): Option[x.type & Symbol] = x match + case sd: SymDenotation => Some(sd.asInstanceOf[x.type & Symbol]) case _ => None - given ClsTest: TypeTest[AnyRef, ClassSymbol] with - def unapply(x: AnyRef): Option[x.type & ClassSymbol] = x match - case cd: ClassDenotation => Some(cd.asInstanceOf) + given ClsTest: TypeTest[Any, ClassSymbol] with + def unapply(x: Any): Option[x.type & ClassSymbol] = x match + case cd: ClassDenotation => Some(cd.asInstanceOf[x.type & ClassSymbol]) case _ => None end TypeTests + implicit def eqSymbol: CanEqual[Symbol, Symbol] = CanEqual.derived + /** A Symbol represents a Scala definition/declaration or a package. * @param coord The coordinates of the symbol (a position or an index) * @param id A unique identifier of the symbol (unique per ContextBase) - */ class Symbol private[Symbols] () extends ParamInfo, SrcPos, Named, printing.Showable { @@ -95,6 +93,7 @@ object Symbols { override def hashCode(): Int = Symbols.id(this) // for debugging. } + */ type TermSymbol = Symbol { type ThisName = TermName } type TypeSymbol = Symbol { type ThisName = TypeName } @@ -104,7 +103,7 @@ object Symbols { inline def asSymbol: Symbol = x.asInstanceOf[Symbol] extension (_self: Symbol) - def self = _self.initialDenot + def self: SymDenotation = _self private def lastDenot: SymDenotation = self.lastDenot private def lastDenot_=(d: SymDenotation): Unit = self.lastDenot = d @@ -154,20 +153,14 @@ object Symbols { private[core] def denot_=(d: SymDenotation): Unit = util.Stats.record("Symbol.denot_=") lastDenot = d - self.checkedPeriod = Nowhere /** The current denotation of this symbol */ def denot(using Context): SymDenotation = util.Stats.record("Symbol.denot") val lastd = lastDenot - if self.checkedPeriod.code == ctx.period.code then lastd - else computeDenot(lastd) - - def computeDenot(lastd: SymDenotation)(using Context): SymDenotation = - util.Stats.record("Symbol.computeDenot") - val now = ctx.period - self.checkedPeriod = now - if lastd.validFor contains now then lastd else recomputeDenot(lastd) + if lastd.validFor.code.containsSinglePhasePeriod(ctx.period.code) + then lastd + else recomputeDenot(lastd) private def recomputeDenot(lastd: SymDenotation)(using Context): SymDenotation = util.Stats.record("Symbol.recomputeDenot") @@ -454,16 +447,16 @@ object Symbols { end extension type TreeOrProvider = TreeProvider | Tree - +/* class ClassSymbol private[Symbols] extends Symbol { util.Stats.record("ClassSymbol") type ThisName = TypeName } - +*/ extension (_self: ClassSymbol) - def self = _self.initialDenot + def self: ClassDenotation = _self /** If this is a top-level class and `-Yretain-trees` (or `-from-tasty`) is set. * Returns the TypeDef tree (possibly wrapped inside PackageDefs) for this class, otherwise EmptyTree. @@ -535,16 +528,7 @@ object Symbols { end extension - @sharable object NoSymbol extends Symbol { - //override def coord = NoCoord - //override def id = 0 - //override def nestingLevel = 0 - //override def defTree = tpd.EmptyTree - //override def associatedFile(using Context): AbstractFile | Null = NoSource.file - //override def recomputeDenot(lastd: SymDenotation)(using Context): SymDenotation = NoDenotation - } - - NoDenotation // force it in order to set `denot` field of NoSymbol + def NoSymbol: Symbol = NoDenotation /** Makes all denotation operations available on symbols */ implicit def toDenot(sym: Symbol)(using Context): SymDenotation = sym.denot @@ -579,11 +563,9 @@ object Symbols { privateWithin: Symbol = NoSymbol, coord: Coord = NoCoord, nestingLevel: Int = ctx.nestingLevel): Symbol { type ThisName = N } = { - val sym = new Symbol().asInstanceOf[Symbol { type ThisName = N }] - val denot = SymDenotation(sym, SymCommon(coord, ctx.base.nextSymId, nestingLevel), owner, name, flags, info, privateWithin) - sym.initialDenot = denot - sym.denot_=(denot) - sym + val sym = SymDenotation(null, SymCommon(coord, ctx.base.nextSymId, nestingLevel), owner, name, flags, info, privateWithin) + sym.denot_=(sym) + sym.asInstanceOf[Symbol { type ThisName = N }] } /** Create a class symbol from its non-info fields and a function @@ -598,11 +580,9 @@ object Symbols { coord: Coord = NoCoord, assocFile: AbstractFile | Null = null)(using Context): ClassSymbol = { - val cls = new ClassSymbol() - val denot = SymDenotation(cls, ClassCommon(coord, ctx.base.nextSymId, ctx.nestingLevel, assocFile), owner, name, flags, NoType, privateWithin) - cls.initialDenot = denot - cls.denot_=(denot) - denot.info = infoFn(cls) + val cls = SymDenotation(null, ClassCommon(coord, ctx.base.nextSymId, ctx.nestingLevel, assocFile), owner, name, flags, NoType, privateWithin).asClass + cls.denot_=(cls) + cls.info = infoFn(cls) cls } diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerDataCollector.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerDataCollector.scala index 9bc7131fc643..61496166bfe0 100644 --- a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerDataCollector.scala +++ b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerDataCollector.scala @@ -5,6 +5,7 @@ import scala.quoted._ import dotty.tools.scaladoc.tasty.SymOps._ import dotty.tools.dotc.core._ import dotty.tools.dotc.util.{ SourceFile => CSourceFile, NoSource } +import Symbols.TypeTests.given class SnippetCompilerDataCollector[Q <: Quotes](val qctx: Q): import qctx.reflect._ From 110dd20d46cfbdca116fa9c107d2db3a610c51e8 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 29 Jan 2023 21:06:22 +0100 Subject: [PATCH 22/23] Streamlining --- .../tools/dotc/core/SymDenotations.scala | 13 + .../src/dotty/tools/dotc/core/Symbols.scala | 268 +++++++----------- .../tools/dotc/transform/ExplicitOuter.scala | 3 +- 3 files changed, 122 insertions(+), 162 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 1d19947a145a..c903ad4d78ac 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1818,6 +1818,19 @@ object SymDenotations { override def hashCode = common.id // for debugging + /** The current denotation of this symbol */ + def currentDenot(using Context): SymDenotation = + util.Stats.record("Symbol.denot") + val valid = validFor.code + // Next condition is inlined from Periods.containsSinglePhasePeriod + if ((valid - ctx.period.code) >>> PhaseWidth) <= (valid & PhaseMask) + then this + else recomputeDenot() + + private def recomputeDenot()(using Context): SymDenotation = + util.Stats.record("Symbol.recomputeDenot") + symbol.setLastDenot(currentSymDenot) + // ---- ParamInfo bindings ------------------------------------- type ThisName <: Name diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 97e15847db79..8f522d4f7698 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -60,41 +60,6 @@ object Symbols { implicit def eqSymbol: CanEqual[Symbol, Symbol] = CanEqual.derived - /** A Symbol represents a Scala definition/declaration or a package. - * @param coord The coordinates of the symbol (a position or an index) - * @param id A unique identifier of the symbol (unique per ContextBase) - class Symbol private[Symbols] () - extends ParamInfo, SrcPos, Named, printing.Showable { - - util.Stats.record(s"new ${getClass}") - - var initialDenot: SymDenotation = _ - - def isClass: Boolean = isInstanceOf[ClassSymbol] - - // SrcPos types and methods - final def span: Span = initialDenot.span - final def sourcePos(using Context): SourcePosition = initialDenot.sourcePos - final def srcPos: SrcPos = initialDenot.srcPos - - // ParamInfo types and methods - def isTypeParam(using Context): Boolean = this.denot.is(TypeParam) - def paramName(using Context): ThisName = this.denot.paramName.asInstanceOf - def paramInfo(using Context): Type = this.denot.info - def paramInfoAsSeenFrom(pre: Type)(using Context): Type = this.denot.paramInfoAsSeenFrom(pre) - def paramInfoOrCompleter(using Context): Type = this.denot.paramInfoOrCompleter - def paramVariance(using Context): Variance = this.denot.paramVariance - def paramRef(using Context): TypeRef = this.denot.paramRef - - def toText(printer: Printer): Text = printer.toText(this) - - override def toString: String = - Symbols.lastDenot(this).toString // + "#" + id // !!! DEBUG - - override def hashCode(): Int = Symbols.id(this) // for debugging. - } - */ - type TermSymbol = Symbol { type ThisName = TermName } type TypeSymbol = Symbol { type ThisName = TypeName } @@ -102,19 +67,14 @@ object Symbols { inline def isSymbol: Boolean = x.isInstanceOf[Symbol] inline def asSymbol: Symbol = x.asInstanceOf[Symbol] - extension (_self: Symbol) - def self: SymDenotation = _self - - private def lastDenot: SymDenotation = self.lastDenot - private def lastDenot_=(d: SymDenotation): Unit = self.lastDenot = d - + extension (self: Symbol) /** A unique identifier of the symbol (unique per ContextBase) */ def id: Int = self.common.id def nestingLevel: Int = self.common.nestingLevel /** The coordinates of the symbol (a position or an index) */ - def coord: Coord = lastDenot.common.coord + def coord: Coord = self.common.coord /** Set the coordinate of this class, this is only useful when the coordinate is * not known at symbol creation. This is the case for root symbols @@ -126,16 +86,16 @@ object Symbols { //assert(myCoord == NoCoord) // This assertion fails for CommentPickling test. // TODO: figure out what's wrong in the setup of CommentPicklingTest and re-enable assertion. - lastDenot.common.coord = c + self.common.coord = c /** The tree defining the symbol at pickler time, EmptyTree if none was retained */ def defTree: Tree = - val dt = lastDenot.common.defTree + val dt = self.common.defTree if dt == null then EmptyTree else dt.nn /** Set defining tree if this symbol retains its definition tree */ def defTree_=(tree: Tree)(using Context): Unit = - if retainsDefTree then lastDenot.common.defTree = tree + if retainsDefTree then self.common.defTree = tree /** Does this symbol retain its definition tree? * A good policy for this needs to balance costs and benefits, where @@ -143,8 +103,8 @@ object Symbols { */ def retainsDefTree(using Context): Boolean = ctx.settings.YretainTrees.value || - denot.owner.isTerm || // no risk of leaking memory after a run for these - denot.isOneOf(InlineOrProxy) || // need to keep inline info + owner.isTerm || // no risk of leaking memory after a run for these + _isOneOf(InlineOrProxy) || // need to keep inline info ctx.settings.YcheckInit.value // initialization check /** Set the denotation of this symbol @@ -152,83 +112,77 @@ object Symbols { */ private[core] def denot_=(d: SymDenotation): Unit = util.Stats.record("Symbol.denot_=") - lastDenot = d + self.lastDenot = d /** The current denotation of this symbol */ def denot(using Context): SymDenotation = - util.Stats.record("Symbol.denot") - val lastd = lastDenot - if lastd.validFor.code.containsSinglePhasePeriod(ctx.period.code) - then lastd - else recomputeDenot(lastd) - - private def recomputeDenot(lastd: SymDenotation)(using Context): SymDenotation = - util.Stats.record("Symbol.recomputeDenot") - val newd = lastd.currentSymDenot - lastDenot = newd - newd + self.lastDenot.currentDenot + + private[core] def setLastDenot(d: SymDenotation): SymDenotation = + self.lastDenot = d + d /** The original denotation of this symbol, without forcing anything */ def originDenotation: SymDenotation = self /** The last known denotation of this symbol, without going through `current` */ - def lastKnownDenotation: SymDenotation = lastDenot + def lastKnownDenotation: SymDenotation = self.lastDenot def classDenot(using Context): ClassDenotation = - _self.denot.asInstanceOf[ClassDenotation] + self.denot.asInstanceOf[ClassDenotation] private[core] def defRunId: RunId = - lastDenot.validFor.runId + self.lastDenot.validFor.runId /** Does this symbol come from a currently compiled source file? */ def isDefinedInCurrentRun(using Context): Boolean = - self.span.exists + span.exists && defRunId == ctx.runId - && lastDenot.associatedFileMatches(ctx.run.nn.files.contains) + && self.lastDenot.associatedFileMatches(ctx.run.nn.files.contains) /** Is this symbol valid in the current run and has an associated file that is * not a binary file. e.g. This will return true for * symbols defined by the user in a prior run of the REPL, that are still valid. */ def isDefinedInSource(using Context): Boolean = - self.span.exists + span.exists && isValidInCurrentRun - && lastDenot.associatedFileMatches(_.extension != "class") + && self.lastDenot.associatedFileMatches(_.extension != "class") def isValidInCurrentRun(using Context): Boolean = - val d = lastDenot + val d = self.lastDenot (d.validFor.runId == ctx.runId || stillValid(d)) - && (d.symbol eq _self) + && (d.symbol eq self) // the last condition is needed because under ctx.staleOK overwritten // members keep denotations pointing to the new symbol, so the validity // periods check out OK. But once a package member is overridden it is not longer // valid. If the option would be removed, the check would be no longer needed. def isTerm(using Context): Boolean = - val lastd = lastDenot + val lastd = self.lastDenot (if lastd.validFor.runId == ctx.runId then lastd else denot).isTerm def isType(using Context): Boolean = - val lastd = lastDenot + val lastd = self.lastDenot (if lastd.validFor.runId == ctx.runId then lastd else denot).isType def asTerm(using Context): TermSymbol = assert(self.isTerm, s"asTerm called on not-a-Term $this" ) - _self.asInstanceOf[TermSymbol] + self.asInstanceOf[TermSymbol] def asType(using Context): TypeSymbol = assert(self.isType, s"isType called on not-a-Type $this"); - _self.asInstanceOf[TypeSymbol] + self.asInstanceOf[TypeSymbol] - def isClass: Boolean = self.isClass + def isClass: Boolean = (self: SymDenotation).isClass - def asClass: ClassSymbol = _self.asInstanceOf[ClassSymbol] + def asClass: ClassSymbol = self.asInstanceOf[ClassSymbol] /** Test whether symbol is private. This conservatively returns `false` * if symbol's denotation is a class that is not yet read. */ def isPrivate(using Context): Boolean = - lastDenot.flagsUNSAFE.is(Private) + self.lastDenot.flagsUNSAFE.is(Private) /** Is the symbol a pattern bound symbol? */ def isPatternBound(using Context): Boolean = @@ -236,21 +190,21 @@ object Symbols { /** The symbol's signature if it is completed or a method, NotAMethod otherwise. */ def signature(using Context): Signature = - if lastDenot.isCompleted || lastDenot.is(Method) then + if self.lastDenot.isCompleted || self.lastDenot.is(Method) then denot.signature else Signature.NotAMethod def isStatic(using Context): Boolean = - self.isStatic + (self: SymDenotation).isStatic /** This symbol entered into owner's scope (owner must be a class). */ - final def entered(using Context): _self.type = + final def entered(using Context): self.type = val d = denot if d.owner.isClass then - d.owner.classDenot.enter(_self) + d.owner.classDenot.enter(self) if d.is(Module) then d.owner.classDenot.enter(d.moduleClass) - _self + self /** Enter this symbol in its class owner after given `phase`. Create a fresh @@ -258,7 +212,7 @@ object Symbols { * that starts being valid after `phase`. * @pre Symbol is a class member */ - def enteredAfter(phase: DenotTransformer)(using Context): _self.type = + def enteredAfter(phase: DenotTransformer)(using Context): self.type = if ctx.phaseId != phase.next.id then atPhase(phase.next)(enteredAfter(phase)) else @@ -270,14 +224,14 @@ object Symbols { if d.is(Module) then d.moduleClass.denot.validFor |= InitialPeriod else owner.classDenot.ensureFreshScopeAfter(phase) - assert(isPrivate || phase.changesMembers, i"$_self entered in $owner at undeclared phase $phase") - _self.entered - case _ => _self + assert(isPrivate || phase.changesMembers, i"$self entered in $owner at undeclared phase $phase") + self.entered + case _ => self /** Remove symbol from scope of owning class */ final def drop()(using Context): Unit = val d = denot - d.owner.classDenot.delete(_self) + d.owner.classDenot.delete(self) if d.is(Module) then d.owner.classDenot.delete(d.moduleClass) /** Remove symbol from scope of owning class after given `phase`. Create a fresh @@ -291,18 +245,18 @@ object Symbols { val d = denot assert(!d.owner._is(Package)) d.owner.classDenot.ensureFreshScopeAfter(phase) - assert(isPrivate || phase.changesMembers, i"$_self deleted in ${d.owner} at undeclared phase $phase") + assert(isPrivate || phase.changesMembers, i"$self deleted in ${d.owner} at undeclared phase $phase") drop() /** This symbol, if it exists, otherwise the result of evaluating `that` */ inline def orElse(inline that: Symbol)(using Context): Symbol = - if denot.exists then _self else that + if denot.exists then self else that /** If this symbol satisfies predicate `p` this symbol, otherwise `NoSymbol` */ - def filter(p: Symbol => Boolean): Symbol = if p(_self) then _self else NoSymbol + def filter(p: Symbol => Boolean): Symbol = if p(self) then self else NoSymbol /** The current name of this symbol */ - def name(using Context): _self.ThisName = denot.name.asInstanceOf[_self.ThisName] + def name(using Context): self.ThisName = denot.name.asInstanceOf[self.ThisName] /** The source or class file from which this class or * the class containing this symbol was generated, null if not applicable. @@ -311,7 +265,7 @@ object Symbols { * Overridden in ClassSymbol */ def associatedFile(using Context): AbstractFile | Null = - lastDenot.associatedFile + self.lastDenot.associatedFile /** The class file from which this class was generated, null if not applicable. */ final def binaryFile(using Context): AbstractFile | Null = @@ -336,7 +290,7 @@ object Symbols { case NoSource => valid(d.owner.source) match case NoSource => - _self match + self match case cls: ClassSymbol => valid(cls.sourceOfClass) case _ if d.is(Module) => valid(d.moduleClass.source) case _ => NoSource @@ -350,7 +304,7 @@ object Symbols { @tailrec final def sourceSymbol(using Context): Symbol = val d = denot if !d.exists then - _self + self else if d.is(ModuleVal) then d.moduleClass.sourceSymbol // The module val always has a zero-extent position else if d.is(Synthetic) then @@ -360,50 +314,50 @@ object Symbols { else if d.isPrimaryConstructor then d.owner.sourceSymbol else - _self - - def exists(using Context): Boolean = _self ne NoSymbol - def owner(using Context): Symbol = _self.denot.owner - def typeParams(using Context): List[TypeSymbol] = _self.denot.typeParams - def thisType(using Context): Type = _self.denot.thisType - def typeRef(using Context): TypeRef = _self.denot.typeRef - def termRef(using Context): TermRef = _self.denot.termRef - def _info(using Context): Type = _self.denot.info - def isCompleted(using Context): Boolean = _self.denot.isCompleted - def isCompleting(using Context): Boolean = _self.denot.isCompleting - def ensureCompleted()(using Context): Unit = _self.denot.ensureCompleted() - def unforcedDecls(using Context): Scope = _self.denot.unforcedDecls - def appliedRef(using Context): Type = _self.denot.appliedRef - def namedType(using Context): NamedType = _self.denot.namedType - def unforcedAnnotation(cls: Symbol)(using Context): Option[Annotation] = _self.denot.unforcedAnnotation(cls) - def children(using Context): List[Symbol] = _self.denot.children - def topLevelClass(using Context): Symbol = _self.denot.topLevelClass - def moduleClass(using Context): Symbol = _self.denot.moduleClass - def sourceModule(using Context): Symbol = _self.denot.sourceModule - def underlyingSymbol(using Context): Symbol = _self.denot.underlyingSymbol - def ownersIterator(using Context): Iterator[Symbol] = _self.denot.ownersIterator - def enclosingClass(using Context): Symbol = _self.denot.enclosingClass - def enclosingMethod(using Context): Symbol = _self.denot.enclosingMethod - def typeParamCreationFlags(using Context): FlagSet = _self.denot.typeParamCreationFlags - def _is(flag: Flag)(using Context): Boolean = _self.denot.is(flag) - def _is(flag: Flag, butNot: FlagSet)(using Context): Boolean = _self.denot.is(flag, butNot) - def _isOneOf(fs: FlagSet)(using Context): Boolean = _self.denot.isOneOf(fs) - def _isOneOf(fs: FlagSet, butNot: FlagSet)(using Context): Boolean = _self.denot.isOneOf(fs, butNot) - def _isAllOf(fs: FlagSet)(using Context): Boolean = _self.denot.isAllOf(fs) - def _isAllOf(fs: FlagSet, butNot: FlagSet)(using Context): Boolean = _self.denot.isAllOf(fs, butNot) + self + + def exists(using Context): Boolean = self ne NoSymbol + def owner(using Context): Symbol = self.denot.owner + def typeParams(using Context): List[TypeSymbol] = self.denot.typeParams + def thisType(using Context): Type = self.denot.thisType + def typeRef(using Context): TypeRef = self.denot.typeRef + def termRef(using Context): TermRef = self.denot.termRef + def _info(using Context): Type = self.denot.info + def isCompleted(using Context): Boolean = self.denot.isCompleted + def isCompleting(using Context): Boolean = self.denot.isCompleting + def ensureCompleted()(using Context): Unit = self.denot.ensureCompleted() + def unforcedDecls(using Context): Scope = self.denot.unforcedDecls + def appliedRef(using Context): Type = self.denot.appliedRef + def namedType(using Context): NamedType = self.denot.namedType + def unforcedAnnotation(cls: Symbol)(using Context): Option[Annotation] = self.denot.unforcedAnnotation(cls) + def children(using Context): List[Symbol] = self.denot.children + def topLevelClass(using Context): Symbol = self.denot.topLevelClass + def moduleClass(using Context): Symbol = self.denot.moduleClass + def sourceModule(using Context): Symbol = self.denot.sourceModule + def underlyingSymbol(using Context): Symbol = self.denot.underlyingSymbol + def ownersIterator(using Context): Iterator[Symbol] = self.denot.ownersIterator + def enclosingClass(using Context): Symbol = self.denot.enclosingClass + def enclosingMethod(using Context): Symbol = self.denot.enclosingMethod + def typeParamCreationFlags(using Context): FlagSet = self.denot.typeParamCreationFlags + def _is(flag: Flag)(using Context): Boolean = self.denot.is(flag) + def _is(flag: Flag, butNot: FlagSet)(using Context): Boolean = self.denot.is(flag, butNot) + def _isOneOf(fs: FlagSet)(using Context): Boolean = self.denot.isOneOf(fs) + def _isOneOf(fs: FlagSet, butNot: FlagSet)(using Context): Boolean = self.denot.isOneOf(fs, butNot) + def _isAllOf(fs: FlagSet)(using Context): Boolean = self.denot.isAllOf(fs) + def _isAllOf(fs: FlagSet, butNot: FlagSet)(using Context): Boolean = self.denot.isAllOf(fs, butNot) // !!! Dotty problem: overloaded extension methods here lead to failures like // Assertion failed: data race? overwriting method isAllOf with method isAllOf in type TermRef(TermRef(TermRef(ThisType(TypeRef(NoPrefix,module class dotc)),object core),object Symbols),isAllOf), // |last sym id = 10301, new sym id = 10299, // |last owner = module class Symbols$, new owner = module class Symbols$, // SrcPos types and methods // !!! make them use lastDenot? - def span: Span = self.span - def sourcePos(using Context): SourcePosition = self.sourcePos - def srcPos: SrcPos = self.srcPos + def span: Span = (self: SymDenotation).span + def sourcePos(using Context): SourcePosition = (self: SymDenotation).sourcePos + def srcPos: SrcPos = (self: SymDenotation).srcPos // ParamInfo types and methods def isTypeParam(using Context): Boolean = denot.is(TypeParam) - def paramName(using Context): _self.ThisName = denot.paramName.asInstanceOf + def paramName(using Context): self.ThisName = denot.paramName.asInstanceOf def paramInfo(using Context): Type = denot.info def paramInfoAsSeenFrom(pre: Type)(using Context): Type = denot.paramInfoAsSeenFrom(pre) def paramInfoOrCompleter(using Context): Type = denot.paramInfoOrCompleter @@ -415,11 +369,11 @@ object Symbols { * the fields in `sym`. */ def copy(using Context)( - owner: Symbol = _self.denot.owner, - name: _self.ThisName = _self.denot.name.asInstanceOf[_self.ThisName], - flags: FlagSet = _self.denot.flags, - info: Type = _self.denot.info, - privateWithin: Symbol = _self.denot.privateWithin, + owner: Symbol = self.denot.owner, + name: self.ThisName = self.denot.name.asInstanceOf[self.ThisName], + flags: FlagSet = self.denot.flags, + info: Type = self.denot.info, + privateWithin: Symbol = self.denot.privateWithin, coord: Coord = NoCoord, // Can be `= owner.coord` once we bootstrap associatedFile: AbstractFile | Null = null // Can be `= owner.associatedFile` once we bootstrap ): Symbol = @@ -433,30 +387,20 @@ object Symbols { // -------- Printing -------------------------------------------------------- - def toText(printer: Printer): Text = printer.toText(_self) + def toText(printer: Printer): Text = printer.toText(self) - def showLocated(using Context): String = ctx.printer.locatedText(_self).show - def showExtendedLocation(using Context): String = ctx.printer.extendedLocationText(_self).show - def showDcl(using Context): String = ctx.printer.dclText(_self).show - def showKind(using Context): String = ctx.printer.kindString(_self) - def showName(using Context): String = ctx.printer.nameString(_self) - def showFullName(using Context): String = ctx.printer.fullNameString(_self) + def showLocated(using Context): String = ctx.printer.locatedText(self).show + def showExtendedLocation(using Context): String = ctx.printer.extendedLocationText(self).show + def showDcl(using Context): String = ctx.printer.dclText(self).show + def showKind(using Context): String = ctx.printer.kindString(self) + def showName(using Context): String = ctx.printer.nameString(self) + def showFullName(using Context): String = ctx.printer.fullNameString(self) - def debugString: String = self.debugString + def debugString: String = (self: SymDenotation).debugString end extension - type TreeOrProvider = TreeProvider | Tree -/* - class ClassSymbol private[Symbols] extends Symbol { - - util.Stats.record("ClassSymbol") - - type ThisName = TypeName - } -*/ - extension (_self: ClassSymbol) - def self: ClassDenotation = _self + extension (self: ClassSymbol) /** If this is a top-level class and `-Yretain-trees` (or `-from-tasty`) is set. * Returns the TypeDef tree (possibly wrapped inside PackageDefs) for this class, otherwise EmptyTree. @@ -469,9 +413,9 @@ object Symbols { * For already loaded trees, we maintain the referenced ids in an attachment. */ def rootTreeContaining(id: String)(using Context): Tree = - _self.denot.infoOrCompleter match + self.denot.infoOrCompleter match case _: NoCompleter => - case _ => _self.denot.ensureCompleted() + case _ => self.denot.ensureCompleted() rootTreeOrProvider match case fn: TreeProvider => if id.isEmpty || fn.mightContain(id) then @@ -483,10 +427,10 @@ object Symbols { if id.isEmpty || mightContain(tree, id) then tree else EmptyTree def rootTreeOrProvider: TreeOrProvider = - _self.lastKnownDenotation.common.asClass.treeOrProvider + self.common.asClass.treeOrProvider private[dotc] def rootTreeOrProvider_=(t: TreeOrProvider)(using Context): Unit = - _self.lastKnownDenotation.common.asClass.treeOrProvider = t + self.common.asClass.treeOrProvider = t private def mightContain(tree: Tree, id: String)(using Context): Boolean = val ids = tree.getAttachment(Ids) match @@ -506,17 +450,17 @@ object Symbols { def assocFile: AbstractFile | Null = self.common.asClass.assocFile def sourceOfClass(using Context): SourceFile = - val common = _self.lastKnownDenotation.common.asClass - if !common.source.exists && !_self._is(Package) then + val common = self.common.asClass + if !common.source.exists && !self._is(Package) then // this allows sources to be added in annotations after `sourceOfClass` is first called - val file = _self.associatedFile + val file = self.associatedFile if file != null && file.extension != "class" then common.source = ctx.getSource(file) else - common.source = defn.patchSource(_self) + common.source = defn.patchSource(self) if !common.source.exists then common.source = atPhaseNoLater(flattenPhase) { - _self.denot.topLevelClass.unforcedAnnotation(defn.SourceFileAnnot) match + self.denot.topLevelClass.unforcedAnnotation(defn.SourceFileAnnot) match case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match case Some(Constant(path: String)) => ctx.getSource(path) case none => NoSource @@ -524,10 +468,12 @@ object Symbols { } common.source - def classInfo(using Context): ClassInfo = _self.classDenot.classInfo + def classInfo(using Context): ClassInfo = self.classDenot.classInfo end extension + type TreeOrProvider = TreeProvider | Tree + def NoSymbol: Symbol = NoDenotation /** Makes all denotation operations available on symbols */ diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index bf51633fcf9c..5fa4f583429a 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -124,7 +124,8 @@ object ExplicitOuter { def ensureOuterAccessors(cls: ClassSymbol)(using Context): Unit = atPhase(explicitOuterPhase.next) { if (!hasOuter(cls)) - newOuterAccessors(cls).foreach(_.enteredAfter(explicitOuterPhase.asInstanceOf[DenotTransformer])) + for outerAcc <- newOuterAccessors(cls) do + outerAcc.enteredAfter(explicitOuterPhase.asInstanceOf[DenotTransformer]) } /** The outer accessor and potentially outer param accessor needed for class `cls` */ From eb993a9aaac4435d1433227de80ed9d1f147e903 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 30 Jan 2023 10:04:53 +0100 Subject: [PATCH 23/23] Bring back checkedPeriod --- compiler/src/dotty/tools/dotc/core/Denotations.scala | 1 + .../src/dotty/tools/dotc/core/SymDenotations.scala | 7 +++++-- compiler/src/dotty/tools/dotc/core/Symbols.scala | 10 +++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 19349f60eee4..a3a7207d1d70 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -237,6 +237,7 @@ object Denotations { final def validFor: Period = myValidFor final def validFor_=(p: Period): Unit = myValidFor = p + symbol.setCheckedPeriod(Nowhere): @unchecked /** Is this denotation different from NoDenotation or an ErrorDenotation? */ def exists: Boolean = true diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index c903ad4d78ac..6c3ed8912114 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1810,6 +1810,7 @@ object SymDenotations { /** The last denotation of this symbol */ var lastDenot: SymDenotation = _ + var checkedPeriod: Period = Nowhere /** Overridden in NoSymbol */ //private[SymDenotations] @@ -1819,11 +1820,13 @@ object SymDenotations { override def hashCode = common.id // for debugging /** The current denotation of this symbol */ - def currentDenot(using Context): SymDenotation = + def computeDenot(using Context): SymDenotation = util.Stats.record("Symbol.denot") val valid = validFor.code + val now = ctx.period + symbol.setCheckedPeriod(now) // Next condition is inlined from Periods.containsSinglePhasePeriod - if ((valid - ctx.period.code) >>> PhaseWidth) <= (valid & PhaseMask) + if ((valid - now.code) >>> PhaseWidth) <= (valid & PhaseMask) then this else recomputeDenot() diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 8f522d4f7698..0a8c29bd2ba6 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -113,15 +113,23 @@ object Symbols { private[core] def denot_=(d: SymDenotation): Unit = util.Stats.record("Symbol.denot_=") self.lastDenot = d + self.checkedPeriod = Nowhere /** The current denotation of this symbol */ def denot(using Context): SymDenotation = - self.lastDenot.currentDenot + util.Stats.record("Symbol.denot") + val lastd = self.lastDenot + if self.checkedPeriod.code == ctx.period.code + then lastd + else lastd.computeDenot private[core] def setLastDenot(d: SymDenotation): SymDenotation = self.lastDenot = d d + def setCheckedPeriod(period: Period): Unit = + self.checkedPeriod = period + /** The original denotation of this symbol, without forcing anything */ def originDenotation: SymDenotation = self