diff options
author | Martin Odersky <odersky@gmail.com> | 2013-01-24 15:20:28 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-01-24 15:21:16 +0100 |
commit | 8621d34646e15b14ffd7ac2a7a8ca6eb587b1426 (patch) | |
tree | 454706fcc58e239ede1dcdb7c67d8bfe8ccc2169 /src/dotty/tools/dotc/core/SymDenotations.scala | |
parent | 6ed74c3a2f38aadfb0bf2110cae00309b9050708 (diff) | |
download | dotty-8621d34646e15b14ffd7ac2a7a8ca6eb587b1426.tar.gz dotty-8621d34646e15b14ffd7ac2a7a8ca6eb587b1426.tar.bz2 dotty-8621d34646e15b14ffd7ac2a7a8ca6eb587b1426.zip |
Various additions to symbols, denotations, and elsewhere
Diffstat (limited to 'src/dotty/tools/dotc/core/SymDenotations.scala')
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 263 |
1 files changed, 243 insertions, 20 deletions
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 |