diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/core/Annotations.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Contexts.scala | 19 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Decorators.scala | 13 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Denotations.scala | 33 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Flags.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Printers.scala | 26 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Scopes.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SubTypers.scala | 14 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 263 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Symbols.scala | 289 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeOps.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 26 |
12 files changed, 493 insertions, 211 deletions
diff --git a/src/dotty/tools/dotc/core/Annotations.scala b/src/dotty/tools/dotc/core/Annotations.scala index 756430fb3..ead92409e 100644 --- a/src/dotty/tools/dotc/core/Annotations.scala +++ b/src/dotty/tools/dotc/core/Annotations.scala @@ -1,8 +1,11 @@ package dotty.tools.dotc.core +import Symbols._ + object Annotations { - abstract class Annotation - abstract class AnnotationInfo + abstract class Annotation { + def matches(cls: Symbol) = ??? + } }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 74b6e851f..645820792 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -7,7 +7,7 @@ import Names._ import Phases._ import Types._ import Symbols._ -import SubTypers._ +import TypeComparers._, Printers._ import collection.mutable import collection.immutable.BitSet @@ -21,27 +21,34 @@ object Contexts { val root: RootContext val period: Period def constraints: Constraints - def subTyper: SubTyper + def typeComparer: TypeComparer + def printer: Printer = ??? def names: NameTable + def enclClass: Context = ??? def phase: Phase = ??? + def owner: Symbol = ??? def erasedTypes: Boolean = ??? } + abstract class DiagnosticsContext(ctx: Context) extends SubContext(ctx) { + var diagnostics: () => String + } + abstract class SubContext(val underlying: Context) extends Context { val root: RootContext = underlying.root val period: Period = underlying.period val constraints = underlying.constraints def names: NameTable = root.names - lazy val subTyper = - if (constraints eq underlying.constraints) underlying.subTyper - else new SubTyper(this) + lazy val typeComparer = + if (constraints eq underlying.constraints) underlying.typeComparer + else new TypeComparer(this) } class RootContext extends Context with Transformers { val underlying: Context = throw new UnsupportedOperationException("RootContext.underlying") - def subTyper: SubTyper = ??? + def typeComparer: TypeComparer = ??? val root: RootContext = this val period = Nowhere diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala index ba3123358..d0ce3efe0 100644 --- a/src/dotty/tools/dotc/core/Decorators.scala +++ b/src/dotty/tools/dotc/core/Decorators.scala @@ -1,6 +1,9 @@ package dotty.tools.dotc package core +import annotation.tailrec +import Symbols._ + import Contexts._, Names._ object Decorators { @@ -15,6 +18,16 @@ object Decorators { context.names.newTermName(s) } + implicit class SymbolIteratorDecorator(val it: Iterator[Symbol]) extends AnyVal { + final def findSymbol(p: Symbol => Boolean): Symbol = { + while (it.hasNext) { + val sym = it.next + if (p(sym)) return sym + } + NoSymbol + } + } + final val MaxRecursions = 1000 implicit class ListDecorator[T](val xs: List[T]) extends AnyVal { diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index 6b19f4589..12b522427 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -8,6 +8,7 @@ import Names.TypeName import Symbols.NoSymbol import Symbols.Symbol import Types._, Periods._, Flags._, Transformers._ +import Decorators.SymbolIteratorDecorator /** Denotations represent the meaning of symbols and named types. @@ -20,10 +21,7 @@ import Types._, Periods._, Flags._, Transformers._ * Lines ending in a horizontal line mean subtying (right is a subtype of left). * * NamedType------NamedTypeWithSignature - * | | | - * | +-----------------------------------------+ - * | | | symbol - * | | v + * | | Symbol---------ClassSymbol * | | | | * | denot | denot | denot | denot @@ -134,7 +132,7 @@ object Denotations { def isType: Boolean = false /** Is this a reference to a term symbol? */ - def isTerm: Boolean = !isType + def isTerm: Boolean = false /** Is this denotation overloaded? */ def isOverloaded = isInstanceOf[MultiDenotation] @@ -150,6 +148,8 @@ object Denotations { def exists: Boolean = true + def filter(p: Symbol => Boolean)(implicit ctx: Context): Denotation + /** Form a denotation by conjoining with denotation `that` */ def & (that: Denotation)(implicit ctx: Context): Denotation = if (this eq that) this @@ -199,8 +199,8 @@ object Denotations { def lubSym(sym1: Symbol, sym2: Symbol): Symbol = { def qualifies(sym: Symbol) = - (sym isAccessibleFrom pre) && (sym2.owner isSubClass sym.owner) - sym1.allOverriddenSymbols find qualifies getOrElse NoSymbol + sym.isAccessibleFrom(pre) && sym2.owner.isSubClass(sym.owner) + sym1.allOverriddenSymbols findSymbol qualifies } def throwError = throw new MatchError(s"$this | $that") @@ -237,11 +237,15 @@ object Denotations { * @param variants The overloaded variants indexed by thheir signatures. */ case class MultiDenotation(denot1: Denotation, denot2: Denotation) extends Denotation { + final override def isType = false + final override def isTerm = true def derivedMultiDenotation(d1: Denotation, d2: Denotation) = if ((d1 eq denot1) && (d2 eq denot2)) this else MultiDenotation(d1, d2) def symbol = unsupported("symbol") def info = unsupported("info") def signature = unsupported("signature") + def filter(p: Symbol => Boolean)(implicit ctx: Context): Denotation = + (denot1 filter p) & (denot2 filter p) def atSignature(sig: Signature): SingleDenotation = denot1.atSignature(sig) orElse denot2.atSignature(sig) def validFor = denot1.validFor & denot2.validFor @@ -252,6 +256,7 @@ object Denotations { abstract class SingleDenotation extends Denotation with DenotationSet { override def isType = symbol.isType + override def isTerm = symbol.isTerm override def signature: Signature = { def sig(tp: Type): Signature = tp match { case tp: PolyType => @@ -272,6 +277,9 @@ object Denotations { def orElse(that: => SingleDenotation) = if (this.exists) this else that + def filter(p: Symbol => Boolean)(implicit ctx: Context): SingleDenotation = + if (p(symbol)) this else NoDenotation + def atSignature(sig: Signature): SingleDenotation = if (sig == signature) this else NoDenotation @@ -346,19 +354,17 @@ object Denotations { current } - def asSymDenotation = asInstanceOf[SymDenotation] + //final def asSymDenotation = asInstanceOf[SymDenotation] // ------ DenotationSet ops ---------------------------------------------- def toDenot(implicit ctx: Context) = this def containsSig(sig: Signature)(implicit ctx: Context) = signature == sig - def filter(p: Symbol => Boolean)(implicit ctx: Context): DenotationSet = - if (p(symbol)) this else NoDenotation def filterDisjoint(denots: DenotationSet)(implicit ctx: Context): DenotationSet = if (denots.containsSig(signature)) NoDenotation else this def filterExcluded(flags: FlagSet)(implicit ctx: Context): DenotationSet = - if (symbol.hasFlag(flags)) NoDenotation else this + if (symbol is flags) NoDenotation else this def filterAccessibleFrom(pre: Type)(implicit ctx: Context): DenotationSet = if (symbol.isAccessibleFrom(pre)) this else NoDenotation def asSeenFrom(pre: Type, owner: Symbol)(implicit ctx: Context): DenotationSet = @@ -394,7 +400,6 @@ object Denotations { def exists: Boolean def toDenot(implicit ctx: Context): Denotation def containsSig(sig: Signature)(implicit ctx: Context): Boolean - def filter(p: Symbol => Boolean)(implicit ctx: Context): DenotationSet def filterDisjoint(denots: DenotationSet)(implicit ctx: Context): DenotationSet def filterExcluded(flags: FlagSet)(implicit ctx: Context): DenotationSet def filterAccessibleFrom(pre: Type)(implicit ctx: Context): DenotationSet @@ -416,8 +421,8 @@ object Denotations { def toDenot(implicit ctx: Context) = denots1.toDenot & denots2.toDenot def containsSig(sig: Signature)(implicit ctx: Context) = (denots1 containsSig sig) || (denots2 containsSig sig) - def filter(p: Symbol => Boolean)(implicit ctx: Context) = - derivedUnion(denots1 filter p, denots2 filter p) + //def filter(p: Symbol => Boolean)(implicit ctx: Context) = + // derivedUnion(denots1 filter p, denots2 filter p) def filterDisjoint(denots: DenotationSet)(implicit ctx: Context): DenotationSet = derivedUnion(denots1 filterDisjoint denots, denots2 filterDisjoint denots) def filterExcluded(flags: FlagSet)(implicit ctx: Context): DenotationSet = diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index 7a3b8f0bc..0e995f756 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -238,7 +238,7 @@ object Flags { final val Local = commonFlag(20, "<local>") /** Symbol is defined by a Java class */ - final val Java = commonFlag(21, "<java>") + final val JavaDefined = commonFlag(21, "<java>") /** A compiler-generated symbol. which is visible for type-checking * (compare with artifact) @@ -344,8 +344,9 @@ object Flags { final val PrivateOrLocal = oneOf(Private, Local) /** Java symbol which is `protected` and `static` */ - final val StaticProtected = allOf(Java, Protected, Static) + final val StaticProtected = allOf(JavaDefined, Protected, Static) /** Labeled `protected[this]` */ final val ProtectedLocal = allOf(Protected, Local) + }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/Printers.scala b/src/dotty/tools/dotc/core/Printers.scala new file mode 100644 index 000000000..67d4d3422 --- /dev/null +++ b/src/dotty/tools/dotc/core/Printers.scala @@ -0,0 +1,26 @@ +package dotty.tools.dotc +package core + +import Types._, Symbols._, Contexts._, Scopes._ + +object Printers { + + abstract class Printer { + def show(tp: Type)(implicit ctx: Context): String + def show(sym: Symbol)(implicit ctx: Context): String + def showLocated(sym: Symbol)(implicit ctx: Context): String + def showDef(sym: Symbol)(implicit ctx: Context): String + def show(sc: Scope)(implicit ctx: Context): String + } + + class StdPrinter extends Printer { + def show(tp: Type)(implicit ctx: Context): String = ??? + def show(sym: Symbol)(implicit ctx: Context): String = ??? + def showLocated(sym: Symbol)(implicit ctx: Context): String = ??? + def showDef(sym: Symbol)(implicit ctx: Context): String = ??? + def show(sc: Scope)(implicit ctx: Context): String = + sc.toList.map(_.showDef).mkString("Scope{\n ", ";\n ", "\n}") + } + + +}
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala index 98f0b6390..0eadb8cb9 100644 --- a/src/dotty/tools/dotc/core/Scopes.scala +++ b/src/dotty/tools/dotc/core/Scopes.scala @@ -114,7 +114,7 @@ object Scopes { * @param sym ... */ def enterUnique(sym: Symbol)(implicit ctx: Context) { - assert(lookup(sym.name) == NoSymbol, (sym.locatedFullString, lookup(sym.name).locatedFullString)) + assert(lookup(sym.name) == NoSymbol, (sym.showLocated, lookup(sym.name).showLocated)) enter(sym) } @@ -270,11 +270,6 @@ object Scopes { @deprecated("Use `toList.reverse` instead", "2.10.0") def reverse: List[Symbol] = toList.reverse - - override def mkString(start: String, sep: String, end: String) = - toList.map(_.defString).mkString(start, sep, end) - - override def toString(): String = mkString("Scope{\n ", ";\n ", "\n}") } /** Create a new scope */ diff --git a/src/dotty/tools/dotc/core/SubTypers.scala b/src/dotty/tools/dotc/core/SubTypers.scala index 29c7b7388..2dcceceba 100644 --- a/src/dotty/tools/dotc/core/SubTypers.scala +++ b/src/dotty/tools/dotc/core/SubTypers.scala @@ -1,18 +1,18 @@ package dotty.tools.dotc.core -import Types._, Contexts._, Symbols._ +import Types._, Contexts._, Symbols._, Flags._ import collection.mutable -object SubTypers { +object TypeComparers { type Constraints = Map[PolyParam, TypeBounds] - object SubTyper { + object TypeComparer { private final val LogPendingSubTypesThreshold = 50 } - class SubTyper(_ctx: Context) extends DotClass { - import SubTyper._ + class TypeComparer(_ctx: Context) extends DotClass { + import TypeComparer._ implicit val ctx = _ctx @@ -72,7 +72,7 @@ object SubTypers { val pre2 = tp2.prefix (sym1 == sym2 && ( ctx.erasedTypes || - sym1.owner.hasFlag(Flags.Package) || + (sym1.owner.isPackage) || isSubType(pre1, pre2)) || tp1.name == tp2.name && @@ -175,7 +175,7 @@ object SubTypers { case tp1: TypeRef => ((tp1 eq defn.NothingType) || - (tp1 eq defn.NullType) && tp2.typeSymbol.containsNull + (tp1 eq defn.NullType) && tp2.typeSymbol.isNonValueClass || (!tp1.symbol.isClass && isSubType(tp1.info.bounds.hi, tp2))) case RefinedType(parent, _) => diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index d92d6eb27..9df52470b 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -6,6 +6,9 @@ import Types._, Flags._, Decorators._, Transformers._ import Scopes.Scope import collection.mutable import collection.immutable.BitSet +import scala.reflect.io.AbstractFile +import Decorators.SymbolIteratorDecorator +import annotation.tailrec object SymDenotations { @@ -51,20 +54,231 @@ object SymDenotations { def annotations_=(annots: List[Annotation]): Unit = _annotations = annots + def hasAnnotation(cls: Symbol) = dropOtherAnnotations(annotations, cls).nonEmpty + + @tailrec + private def dropOtherAnnotations(anns: List[Annotation], cls: Symbol): List[Annotation] = anns match { + case ann :: rest => if (ann matches cls) anns else dropOtherAnnotations(rest, cls) + case Nil => Nil + } + final def isCompleted = _annotations != null - /** is this symbol a class? */ - def isClass: Boolean = false + /** is this denotation a class? */ + final def isClass: Boolean = symbol.isInstanceOf[ClassSymbol] + + /** Special case tests for flags that are known a-priori and do not need loading + * flags. + */ + final def isModule = _flags is Module + final def isModuleObj = _flags is ModuleObj + final def isModuleClass = _flags is ModuleClass + final def isPackage = _flags is Package + final def isPackageObj = _flags is PackageObj + final def isPackageClass = _flags is PackageClass + + /** is this denotation a method? */ + //def isMethod: Boolean = false - /** is this symbol a method? */ - def isMethod: Boolean = false + def isSubClass(cls: Symbol)(implicit ctx: Context) = false + + def isNonBottomSubClass(cls: Symbol)(implicit ctx: Context) = false + + final def isSubClassOrCompanion(base: Symbol)(implicit ctx: Context): Boolean = + isNonBottomSubClass(base) || + isModuleClass && linkedClass.isNonBottomSubClass(base) + + final def enclosingSubClass(implicit ctx: Context) = { + val thissym = symbol + ctx.owner.ownersIterator.findSymbol(_.isSubClass(thissym)) + } /** is this symbol the result of an erroneous definition? */ def isError: Boolean = false + final def ownersIterator(implicit ctx: Context) = new Iterator[Symbol] { + private var current = symbol + def hasNext = current.exists + def next: Symbol = { + val result = current + current = current.owner + result + } + } + + final def hasTransOwner(sym: Symbol)(implicit ctx: Context): Boolean = { + var o = symbol + while ((o ne sym) && (o ne NoSymbol)) o = o.owner + (o eq sym) + } + def withType(tp: Type): SymDenotation = ??? override protected def copy(s: Symbol, i: Type): SingleDenotation = new UniqueRefDenotation(s, i, validFor) + + def moduleClass(implicit ctx: Context): Symbol = + if (this.isModuleObj) info.typeSymbol else NoSymbol + + /** Desire to re-use the field in ClassSymbol which stores the source + * file to also store the classfile, but without changing the behavior + * of sourceFile (which is expected at least in the IDE only to + * return actual source code.) So sourceFile has classfiles filtered out. + */ + private def sourceFileOnly(file: AbstractFile): AbstractFile = + if ((file eq null) || (file.path endsWith ".class")) null else file + + private def binaryFileOnly(file: AbstractFile): AbstractFile = + if ((file eq null) || !(file.path endsWith ".class")) null else file + + final def topLevelClass(implicit ctx: Context): Symbol = + if (!(owner.isPackageClass)) owner.topLevelClass + else if (isClass) symbol + else moduleClass + + final def enclosingPackage(implicit ctx: Context): Symbol = + if (isPackageClass) symbol else owner.enclosingPackage + + def associatedFile(implicit ctx: Context): AbstractFile = topLevelClass.associatedFile + final def binaryFile(implicit ctx: Context): AbstractFile = binaryFileOnly(associatedFile) + final def sourceFile(implicit ctx: Context): AbstractFile = sourceFileOnly(associatedFile) + + /** Is this symbol a type or stable term? */ + final def isStable(implicit ctx: Context) = !( + isTerm && + this.is(UnstableValue, butNot = Stable) || + info.isVolatile && !hasAnnotation(defn.uncheckedStableClass) + ) + + final def matchingSymbol(inClass: Symbol, site: Type)(implicit ctx: Context): Symbol = { + var denot = inClass.info.nonPrivateDecl(name) + if (denot.isTerm) { + val targetType = site.memberInfo(this) + if (denot.isOverloaded) + denot = denot.atSignature(targetType.signature) + if (!(site.memberInfo(denot.asInstanceOf[SymDenotation]) matches targetType)) + denot = NoDenotation + } + denot.symbol + } + + final def overriddenSymbol(inClass: ClassSymbol)(implicit ctx: Context): Symbol = + if (owner isSubClass inClass) matchingSymbol(inClass, owner.thisType) + else NoSymbol + + final def allOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] = + info.baseClasses.tail.iterator map overriddenSymbol filter (_.exists) + + /** Is this symbol defined in the same scope and compilation unit as `that` symbol? */ + private def isCoDefinedWith(that: Symbol)(implicit ctx: Context) = + (this.owner == that.owner) && + ( !(this.owner.isPackageClass) + || (this.sourceFile == null) + || (that.sourceFile == null) + || (this.sourceFile.path == that.sourceFile.path) // Cheap possibly wrong check, then expensive normalization + || (this.sourceFile.canonicalPath == that.sourceFile.canonicalPath) + ) + + def companionModule(implicit ctx: Context): Symbol = + owner.info.decl(name.toTermName).filter(_.isModule).symbol + + def companionClass(implicit ctx: Context): Symbol = + owner.info.decl(name.toTypeName).filter(_.isClass).symbol + + def linkedClass(implicit ctx: Context): Symbol = + if (this.isModuleClass) companionClass + else if (this.isClass) companionModule.moduleClass + else NoSymbol + + final def accessBoundary(base: Symbol)(implicit ctx: Context): Symbol = { + val fs = flags + if (fs is PrivateOrLocal) owner + else if (fs is StaticProtected) defn.RootClass + else if (privateWithin.exists && !ctx.phase.erasedTypes) privateWithin + else if (fs is Protected) base + else defn.RootClass + } + + final def isContainedIn(boundary: Symbol)(implicit ctx: Context): Boolean = + if (symbol eq boundary) true + else if (!this.exists || + (this.isPackageClass) && !(boundary.isPackageClass)) false + else owner.isContainedIn(boundary) + + def isAsAccessibleAs(that: Symbol)(implicit ctx: Context): Boolean = + (that.accessBoundary(NoSymbol) isContainedIn this.accessBoundary(NoSymbol)) && + (this.isStable || !that.isStable) + + def isAccessibleFrom(pre: Type, superAccess: Boolean = false)(implicit ctx: Context): Boolean = { + + def accessWithinLinked(boundary: Symbol) = { + val linked = boundary.linkedClass + (linked ne NoSymbol) && accessWithin(linked) + } + + /** Are we inside definition of `boundary`? */ + def accessWithin(boundary: Symbol) = + owner.hasTransOwner(boundary) && + (!(this is JavaDefined) || + owner.enclosingPackage == boundary.enclosingPackage) + + def isCorrectThisType(pre: Type): Boolean = pre match { + case ThisType(pclazz) => + (pclazz eq owner) || + (this is Protected) && pclazz.isNonBottomSubClass(owner) + case _ => false + } + + /** Is protected access to target symbol permitted? */ + def isProtectedAccessOK = { + def fail(diagnostics: () => String): Boolean = { + ctx match { + case ctx: DiagnosticsContext => ctx.diagnostics = diagnostics + case _ => + } + false + } + val cls = owner.enclosingSubClass + if (!cls.exists) + fail(() => + s"""Access to protected $this not permitted because + |enclosing ${ctx.enclClass.owner.showLocated} is not a subclass of + |${owner.showLocated} where target is defined""".stripMargin) + else if (!(isType || // allow accesses to types from arbitrary subclasses fixes #4737 + pre.widen.typeSymbol.isSubClassOrCompanion(cls) || + cls.isModuleClass && + pre.widen.typeSymbol.isSubClassOrCompanion(cls.linkedClass))) + fail(() => + s"""Access to protected $show not permitted because + |prefix type ${pre.widen.show} does not conform to + |${cls.showLocated} where the access takes place""".stripMargin) + else true + } + + (pre == NoPrefix) || { + val boundary = accessBoundary(owner) + + ( (boundary.isTerm + || (boundary eq defn.RootClass)) + || (accessWithin(boundary) || accessWithinLinked(boundary)) && + ( !(this is Local) + || (owner is ImplClass) // allow private local accesses to impl class members + || isCorrectThisType(pre) + ) + || (this is Protected) && + ( superAccess + || pre.isInstanceOf[ThisType] + || ctx.phase.erasedTypes + || isProtectedAccessOK + ) + ) + } + } + + def isNonValueClass(implicit ctx: Context): Boolean = + isClass && !isSubClass(defn.AnyValClass) + + def show(implicit ctx: Context): String = ??? + def showLocated(implicit ctx: Context): String = ??? } class CompleteSymDenotation( @@ -133,7 +347,7 @@ object SymDenotations { } } - abstract class ClassDenotation(initFlags: FlagSet)(implicit ctx: Context) + abstract class ClassDenotation(initFlags: FlagSet, assocFile: AbstractFile)(implicit ctx: Context) extends SymDenotation(initFlags) { import NameFilter._ import util.LRU8Cache @@ -148,6 +362,8 @@ object SymDenotations { val info = ClassInfo(owner.thisType, this) + override def associatedFile(implicit ctx: Context): AbstractFile = assocFile + private var memberCacheVar: LRU8Cache[Name, DenotationSet] = null private def memberCache: LRU8Cache[Name, DenotationSet] = { @@ -220,10 +436,15 @@ object SymDenotations { baseClassesVar } - /** Is this class a subclass of `clazz`? */ - final def isSubClass(clazz: ClassSymbol)(implicit ctx: Context): Boolean = { - superClassBits contains clazz.superId - } + final override def isNonBottomSubClass(cls: Symbol)(implicit ctx: Context): Boolean = + (symbol eq cls) || + (superClassBits contains cls.superId) || + (this is Erroneous) || + (cls is Erroneous) && cls.isClass + + final override def isSubClass(cls: Symbol)(implicit ctx: Context) = + isNonBottomSubClass(cls) || + cls.isClass && ((symbol eq defn.NothingClass) || (symbol eq defn.NullClass)) private var definedFingerPrintCache: FingerPrint = null @@ -281,17 +502,17 @@ object SymDenotations { } final def membersNamed(name: Name)(implicit ctx: Context): DenotationSet = { - var refs: DenotationSet = memberCache lookup name - if (refs == null) { + var denots: DenotationSet = memberCache lookup name + if (denots == null) { if (containsName(definedFingerPrint, name)) { val ownDenots = decls.denotsNamed(name) - refs = ownDenots + denots = ownDenots var ps = parents while (ps.nonEmpty) { val parentSym = ps.head.typeSymbol parentSym.denot match { case parentd: ClassDenotation => - refs = refs union + denots = denots union parentd.membersNamed(name) .filterExcluded(Flags.Private) .asSeenFrom(thisType, parentSym) @@ -300,11 +521,11 @@ object SymDenotations { } } } else { - refs = NoDenotation + denots = NoDenotation } - memberCache enter (name, refs) + memberCache enter (name, denots) } - refs + denots } private var baseTypeCache: java.util.HashMap[CachedType, Type] = null @@ -374,15 +595,17 @@ object SymDenotations { initFlags: FlagSet, val typeParams: List[TypeSymbol], val parents: List[Type], - val decls: Scope - )(implicit ctx: Context) extends ClassDenotation(initFlags) + val decls: Scope, + assocFile: AbstractFile = null + )(implicit ctx: Context) extends ClassDenotation(initFlags, assocFile) abstract class LazyClassDenotation( val symbol: ClassSymbol, val owner: Symbol, val name: Name, - initFlags: FlagSet - )(implicit ctx: Context) extends ClassDenotation(initFlags) with LazyCompletion { + initFlags: FlagSet, + assocFile: AbstractFile = null + )(implicit ctx: Context) extends ClassDenotation(initFlags, assocFile) with LazyCompletion { protected var _typeParams: List[TypeSymbol] = null protected var _parents: List[Type] = null diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index 9c8738527..decdb6c84 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -13,13 +13,14 @@ import SymDenotations._ import Types._, Annotations._ import Denotations.{Denotation, SingleDenotation, MultiDenotation} import collection.mutable +import reflect.io.AbstractFile object Symbols { /** A Symbol represents a Scala definition/declaration or a package. */ - abstract class Symbol { + abstract class Symbol(denotf: Symbol => SymDenotation) { /** Is symbol different from NoSymbol? */ def exists = true @@ -27,82 +28,156 @@ object Symbols { /** This symbol, if it exists, otherwise the result of evaluating `that` */ def orElse(that: => Symbol) = if (exists) this else that - /** Set the denotation of this symbol. - */ - def setDenotation(denot: SymDenotation) = - lastDenot = denot + def filter(p: Symbol => Boolean): Symbol = if (p(this)) this else NoSymbol /** The last denotation of this symbol */ - protected[this] var lastDenot: SymDenotation = null + private[this] var lastDenot: SymDenotation = denotf(this) - /** Load denotation of this symbol */ - protected def loadDenot(implicit ctx: Context): SymDenotation + final def denot(implicit ctx: Context): SymDenotation = { + var denot = lastDenot + if (!(denot.validFor contains ctx.period)) denot = denot.current.asInstanceOf[SymDenotation] + denot + } - /** The denotation of this symbol + def isType: Boolean = false + def isTerm: Boolean = false + def isClass: Boolean = false + + /** Special case tests for flags that are known a-priori and do not need loading + * flags. */ - def denot(implicit ctx: Context): SymDenotation = { - val denot = lastDenot - if (denot == null) loadDenot - else { - val currentPeriod = ctx.period - val valid = denot.validFor - if (valid contains currentPeriod) denot - else if (valid.runId != currentPeriod.runId) reloadDenot - else denot.current.asSymDenotation - } - } + def isModule(implicit ctx: Context) = denot.isModule + def isModuleObj(implicit ctx: Context) = denot.isModuleObj + def isModuleClass(implicit ctx: Context) = denot.isModuleClass + def isPackage(implicit ctx: Context) = denot.isPackage + def isPackageObj(implicit ctx: Context) = denot.isPackageObj + def isPackageClass(implicit ctx: Context) = denot.isPackageClass + + /** A unique, densely packed integer tag for each class symbol, -1 + * for all other symbols. To save memory, this method + * should be called only if class is a super class of some other class. + */ + def superId: Int = -1 + +// --------- Forwarders for sym methods -------------------------- + + /** The current owner of this symbol */ + final def owner(implicit ctx: Context): Symbol = denot.owner - /** - * Get loaded denotation if lastDenot points to a denotation from - * a different run. !!! needed? + /** The current name of this symbol */ + final def name(implicit ctx: Context): Name = denot.name + + /** The current type info of this symbol */ + final def info(implicit ctx: Context): Type = denot.info + + /** The current flag set of this symbol */ + final def flags(implicit ctx: Context): FlagSet = denot.flags + + /** The current privateWithin boundary of this symbol, NoSymbol if no boundary is given. */ + final def privateWithin(implicit ctx: Context): Symbol = denot.privateWithin + + /** The current annotations of this symbol */ + final def annotations(implicit ctx: Context): List[Annotation] = denot.annotations + + /** Does this symbol have an annotation matching the given class symbol? */ + final def hasAnnotation(cls: Symbol)(implicit ctx: Context): Boolean = denot.hasAnnotation(cls) + + /** The chain of owners of this symbol, starting with the symbol itself */ + final def ownersIterator(implicit ctx: Context): Iterator[Symbol] = denot.ownersIterator + + /** Same as `ownersIterator contains sym` but more efficient. */ + final def hasTransOwner(sym: Symbol)(implicit ctx: Context): Boolean = denot.hasTransOwner(sym) + + /** The top-level class containing this symbol, except for a toplevel module + * its module class */ - private def reloadDenot(implicit ctx: Context): SymDenotation = { - val initDenot = lastDenot.initial.asSymDenotation - val newSym: Symbol = - ctx.atPhase(FirstPhaseId) { implicit ctx => - initDenot.owner.info.decl(initDenot.name) - .atSignature(denot.signature).symbol - } - if (newSym eq this) { // no change, change validity - var d = initDenot - do { - d.validFor = Period(ctx.runId, d.validFor.firstPhaseId, d.validFor.lastPhaseId) - d = d.nextInRun.asSymDenotation - } while (d ne initDenot) - } - newSym.denot - } + def topLevelClass(implicit ctx: Context): Symbol = denot.topLevelClass + + /** The package containing this symbol */ + def enclosingPackage(implicit ctx: Context): Symbol = denot.enclosingPackage + + final def associatedFile(implicit ctx: Context): AbstractFile = denot.associatedFile + final def binaryFile(implicit ctx: Context): AbstractFile = denot.binaryFile + final def sourceFile(implicit ctx: Context): AbstractFile = denot.sourceFile + + final def companionClass(implicit ctx: Context): Symbol = denot.companionClass + + final def companionModule(implicit ctx: Context): Symbol = denot.companionModule + + final def linkedClass(implicit ctx: Context): Symbol = denot.linkedClass + + /** Is this symbol a subclass of the given class? */ + final def isSubClass(cls: Symbol)(implicit ctx: Context): Boolean = denot.isSubClass(cls) + + /** Is this class symbol a subclass of `cls`, + * and is this class symbol also different from Null or Nothing? + */ + final def isNonBottomSubClass(cls: Symbol)(implicit ctx: Context): Boolean = denot.isNonBottomSubClass(cls) + + /** Is this symbol a subclass of `base` or a companion object of such a subclass? */ + final def isSubClassOrCompanion(base: Symbol)(implicit ctx: Context): Boolean = denot.isSubClassOrCompanion(base) + + /** The class that encloses the owner of the current context + * and that is a subclass of this class. + */ + final def enclosingSubClass(implicit ctx: Context) = denot.enclosingSubClass + + ///** Is this symbol a proper subclass of the given class? */ + //def isProperSubClass(cls: ClassSymbol)(implicit ctx: Context): Boolean = (this ne cls) && this.isSubClass(cls) + + /** The non-private symbol whose type matches the type of this symbol + * in in given class. + * + * @param inClass The class containing the symbol's definition + * @param site The base type from which member types are computed + */ + final def matchingSymbol(inClass: Symbol, site: Type)(implicit ctx: Context): Symbol = denot.matchingSymbol(inClass, site) + + /** The symbol, in class `inClass`, that is overridden by this symbol. */ + final def overriddenSymbol(inClass: ClassSymbol)(implicit ctx: Context): Symbol = denot.overriddenSymbol(inClass) - def isType: Boolean - def isTerm = !isType + /** All symbols overriden by this symbol. */ + final def allOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] = denot.allOverriddenSymbols + /** The class or term symbol up to which this symbol is accessible, + * or RootClass if it is public. As java protected statics are + * otherwise completely inaccessible in scala, they are treated + * as public. + * @param base + */ + final def accessBoundary(base: Symbol)(implicit ctx: Context): Symbol = denot.accessBoundary(base) + /** Is this symbol contained in `boundary`? */ + final def isContainedIn(boundary: Symbol)(implicit ctx: Context): Boolean = denot.isContainedIn(boundary) - // forwarders for sym methods - def owner(implicit ctx: Context): Symbol = denot.owner - def name(implicit ctx: Context): Name = denot.name - def flags(implicit ctx: Context): FlagSet = denot.flags - def info(implicit ctx: Context): Type = denot.info + /** Is this symbol accessible whenever `that` symbol is accessible? + * Does not take into account status of protected members. + */ + final def isAsAccessibleAs(that: Symbol)(implicit ctx: Context): Boolean = denot.isAsAccessibleAs(that) + + /** Is this symbol a non-value class? */ + final def isNonValueClass(implicit ctx: Context): Boolean = denot.isNonValueClass + + /** Is this symbol accessible as a member of tree with type `pre`? + * @param pre The type of the tree from which the selection is made + * @param superAccess Access is via super + */ + final def isAccessibleFrom(pre: Type, superAccess: Boolean = false)(implicit ctx: Context): Boolean = denot.isAccessibleFrom(pre, superAccess) + + def show(implicit ctx: Context): String = ctx.printer.show(this) + def showLocated(implicit ctx: Context): String = ctx.printer.showLocated(this) + def showDef(implicit ctx: Context): String = ctx.printer.showDef(this) - def prefix(implicit ctx: Context) = owner.thisType - def allOverriddenSymbols: Iterator[Symbol] = ??? - def isAsAccessibleAs(other: Symbol): Boolean = ??? - def isAccessibleFrom(pre: Type)(implicit ctx: Context): Boolean = ??? - def locationString: String = ??? - def locatedFullString: String = ??? - def defString: String = ??? def typeParams: List[TypeSymbol] = ??? def unsafeTypeParams: List[TypeSymbol] = ??? def thisType: Type = ??? def isStaticMono = isStatic && typeParams.isEmpty - def isPackageClass: Boolean = ??? def isRoot: Boolean = ??? def moduleClass: Symbol = ??? def cloneSymbol: Symbol = ??? def hasAnnotation(ann: Annotation): Boolean = ??? def hasAnnotation(ann: ClassSymbol): Boolean = ??? - def asTerm: TermSymbol = ??? def asType: TypeSymbol = ??? def asClass: ClassSymbol = ??? @@ -116,91 +191,24 @@ object Symbols { def isConcrete = !isDeferred def isJava: Boolean = ??? - def isSubClass(that: Symbol): Boolean = ??? - def isNonBottomSubClass(that: Symbol): Boolean = ??? - def isProperSubClass(that: Symbol): Boolean = - (this ne that) && (this isSubClass that) - - def privateWithin(implicit ctx: Context): Symbol = denot.privateWithin def isAbstractType: Boolean = ??? def newAbstractType(name: TypeName, info: TypeBounds): TypeSymbol = ??? def newAbstractTerm(name: TermName, tpe: Type): TypeSymbol = ??? - def isClass: Boolean = false - def isMethod(implicit ctx: Context): Boolean = denot.isMethod - def hasFlag(required: FlagSet)(implicit ctx: Context): Boolean = (flags & required) != Flags.Empty - def hasAllFlags(required: FlagSet)(implicit ctx: Context): Boolean = (flags & required) == flags - - /** The non-private symbol whose type matches the type of this symbol - * in in given class. - * - * @param ofClass The class containing the symbol's definition - * @param site The base type from which member types are computed - */ - final def matchingSymbol(inClass: Symbol, site: Type)(implicit ctx: Context): Symbol = { - var ref = inClass.info.nonPrivateDecl(name) - if (ref.isTerm) { - val targetType = site.memberInfo(this) - if (ref.isOverloaded) ref = ref.atSignature(targetType.signature) - val candidate = ref.symbol - if (site.memberInfo(candidate) matches targetType) candidate - else NoSymbol - } else ref.symbol - } - - def overriddenSymbol(inClass: ClassSymbol)(implicit ctx: Context): Symbol = - if (owner isSubClass inClass) matchingSymbol(inClass, owner.thisType) - else NoSymbol + //def isMethod(implicit ctx: Context): Boolean = denot.isMethod - def isStable(implicit ctx: Context): Boolean = false + def isStable(implicit ctx: Context): Boolean = denot.isStable - /** The class or term symbol up to which this symbol is accessible, - * or RootClass if it is public. As java protected statics are - * otherwise completely inaccessible in scala, they are treated - * as public. - * @param base - */ - def accessBoundary(base: Symbol)(implicit ctx: Context): Symbol = { - val denot = this.denot - val fs = denot.flags - if (fs is PrivateOrLocal) owner - else if (fs is StaticProtected) defn.RootClass - else if (denot.privateWithin.exists && !ctx.phase.erasedTypes) denot.privateWithin - else if (fs is Protected) base - else defn.RootClass - } - - /** Is this symbol contained in `boundary`? */ - def isContainedIn(boundary: Symbol)(implicit ctx: Context): Boolean = - if (this eq boundary) true - else if (!this.exists || - (this is PackageClass) && !(boundary is PackageClass)) false - else owner.isContainedIn(boundary) - - /** Is this symbol accessible whenever `that` symbol is accessible? - * Does not take into account status of protected members. - */ - def isAsAccessible(that: Symbol)(implicit ctx: Context): Boolean = - (that.accessBoundary(NoSymbol) isContainedIn this.accessBoundary(NoSymbol)) && - this.isStable || !that.isStable - - def containsNull(implicit ctx: Context): Boolean = - isClass && !(isSubClass(defn.AnyValClass)) } - abstract class TermSymbol extends Symbol { + abstract class TermSymbol(denotf: Symbol => SymDenotation) extends Symbol(denotf) { def name: TermName - def isType = true - - override def isStable(implicit ctx: Context) = !( - this.is(UnstableValue, butNot = Stable) || - info.isVolatile && !hasAnnotation(defn.uncheckedStableClass) - ) + override def isTerm = true } - abstract class TypeSymbol extends Symbol { + abstract class TypeSymbol(denotf: Symbol => SymDenotation) extends Symbol(denotf) { def name: TypeName - def isType = false + override def isType = true def variance: Int = ??? @@ -208,23 +216,20 @@ object Symbols { def typeTemplate(implicit ctx: Context): Type = ??? } - abstract class ClassSymbol extends TypeSymbol { + abstract class ClassSymbol(denotf: Symbol => ClassDenotation) extends TypeSymbol(denotf) { override def isClass = true private var superIdHint: Int = -1 - override def denot(implicit ctx: Context): ClassDenotation = - super.denot.asInstanceOf[ClassDenotation] + final def classDenot(implicit ctx: Context): ClassDenotation = + denot.asInstanceOf[ClassDenotation] def typeOfThis(implicit ctx: Context): Type = ??? - def baseClasses(implicit ctx: Context): List[ClassSymbol] = denot.baseClasses + def baseClasses(implicit ctx: Context): List[ClassSymbol] = classDenot.baseClasses - override def typeConstructor(implicit ctx: Context): Type = denot.typeConstructor - override def typeTemplate(implicit ctx: Context): Type = denot.typeTemplate + override def typeConstructor(implicit ctx: Context): Type = classDenot.typeConstructor + override def typeTemplate(implicit ctx: Context): Type = classDenot.typeTemplate - /** The unique, densely packed identifier of this class symbol. Should be called - * only if class is a super class of some other class. - */ def superId(implicit ctx: Context): Int = { val hint = superIdHint val rctx = ctx.root @@ -245,11 +250,13 @@ object Symbols { } } - object NoSymbol extends Symbol { - def loadDenot(implicit ctx: Context): SymDenotation = NoDenotation + class ErrorSymbol(underlying: Symbol, msg: => String)(implicit ctx: Context) extends Symbol(sym => underlying.denot) { + override def isType = underlying.isType + override def isTerm = underlying.isTerm + } + + object NoSymbol extends Symbol(sym => NoDenotation) { override def exists = false - def isType = false - override def isTerm = false } implicit def defn(implicit ctx: Context): Definitions = ctx.root.definitions diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala index 8b4952489..8fb3d69a0 100644 --- a/src/dotty/tools/dotc/core/TypeOps.scala +++ b/src/dotty/tools/dotc/core/TypeOps.scala @@ -31,7 +31,7 @@ trait TypeOps { this: Context => ErrorType // don't be overzealous with throwing exceptions, see #2641 else throw new Error( - s"something is wrong (wrong class file?): ${tparam.locationString} cannot be instantiated from ${pre.widen}") + s"something is wrong (wrong class file?): ${tparam.showLocated} cannot be instantiated from ${pre.widen.show}") def prefixMatches = pre.typeSymbol isNonBottomSubClass tparamOwner diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index dc8c7c9f1..624720d50 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -3,7 +3,7 @@ package core import util.HashSet import Symbols._ -import SubTypers._ +import TypeComparers._ import Flags._ import Names._ import Scopes._ @@ -314,13 +314,13 @@ object Types { /** Is this type a subtype of that type? */ final def <:<(that: Type)(implicit ctx: Context): Boolean = - ctx.subTyper.isSubType(this, that) + ctx.typeComparer.isSubType(this, that) /** Is this type the same as that type? * This is the case iff `this <:< that` and `that <:< this`. */ final def =:=(that: Type)(implicit ctx: Context): Boolean = - ctx.subTyper.isSameType(this, that) + ctx.typeComparer.isSameType(this, that) /** Is this type close enough to that type so that members * with the two type would override each other? @@ -335,15 +335,15 @@ object Types { * poly types. */ def matches(that: Type)(implicit ctx: Context): Boolean = - ctx.subTyper.matchesType(this, that, !ctx.phase.erasedTypes) + ctx.typeComparer.matchesType(this, that, !ctx.phase.erasedTypes) /** Does this type match that type * */ /** The info of `sym`, seen as a member of this type. */ - final def memberInfo(sym: Symbol)(implicit ctx: Context): Type = { - sym.info.asSeenFrom(this, sym.owner) + final def memberInfo(denot: SymDenotation)(implicit ctx: Context): Type = { + denot.info.asSeenFrom(this, denot.owner) } /** Widen from singleton type to its underlying non-singleton @@ -447,7 +447,9 @@ object Types { def |(that: Type)(implicit ctx: Context): Type = ctx.lub(this, that) - // hashing + def show(implicit ctx: Context): String = ctx.printer.show(this) + +// ----- hashing ------------------------------------------------------ /** customized hash code of this type. * NotCached for uncached types. Cached types @@ -978,15 +980,15 @@ object Types { // ----- AnnotatedTypes ----------------------------------------------------------- - case class AnnotatedType(annots: List[AnnotationInfo], tpe: Type) extends UncachedProxyType { + case class AnnotatedType(annots: List[Annotation], tpe: Type) extends UncachedProxyType { override def underlying(implicit ctx: Context): Type = tpe - def derivedAnnotatedType(annots1: List[AnnotationInfo], tpe1: Type) = + def derivedAnnotatedType(annots1: List[Annotation], tpe1: Type) = if ((annots1 eq annots) && (tpe1 eq tpe)) this else AnnotatedType.make(annots1, tpe1) } object AnnotatedType { - def make(annots: List[AnnotationInfo], underlying: Type) = + def make(annots: List[Annotation], underlying: Type) = if (annots.isEmpty) underlying else AnnotatedType(annots, underlying) } @@ -1060,7 +1062,7 @@ object Types { tp } - def mapOverAnnotations(annots: List[AnnotationInfo]): List[AnnotationInfo] = ??? + def mapOverAnnotations(annots: List[Annotation]): List[Annotation] = ??? } @@ -1090,7 +1092,7 @@ object Types { abstract class TypeAccumulator[T] extends ((T, Type) => T) { def apply(x: T, tp: Type): T - def apply(x: T, annot: AnnotationInfo): T = ??? + def apply(x: T, annot: Annotation): T = ??? def foldOver(x: T, tp: Type): T = tp match { case tp: NamedType => |