diff options
Diffstat (limited to 'src/dotty/tools/dotc/core')
18 files changed, 322 insertions, 115 deletions
diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala index 155ea87e0..cd7b46896 100644 --- a/src/dotty/tools/dotc/core/Decorators.scala +++ b/src/dotty/tools/dotc/core/Decorators.scala @@ -143,7 +143,7 @@ object Decorators { * 2) Lists can be formatted using the desired separator between two `%` signs, * eg `i"myList = (${myList}%, %)"` */ - implicit class InfoString(val sc: StringContext) extends AnyVal { + implicit class StringInterpolators(val sc: StringContext) extends AnyVal { def i(args: Any*)(implicit ctx: Context): String = { @@ -166,7 +166,39 @@ object Decorators { val (args1, suffixes1) = (args, suffixes).zipped.map(treatArg(_, _)).unzip new StringContext(prefix :: suffixes1.toList: _*).s(args1: _*) } - } + /** Lifted from scala.reflect.internal.util + * A safe combination of [[scala.collection.immutable.StringLike#stripMargin]] + * and [[scala.StringContext#raw]]. + * + * The margin of each line is defined by whitespace leading up to a '|' character. + * This margin is stripped '''before''' the arguments are interpolated into to string. + * + * String escape sequences are '''not''' processed; this interpolater is designed to + * be used with triple quoted Strings. + * + * {{{ + * scala> val foo = "f|o|o" + * foo: String = f|o|o + * scala> sm"""|${foo} + * |""" + * res0: String = + * "f|o|o + * " + * }}} + */ + final def sm(args: Any*): String = { + def isLineBreak(c: Char) = c == '\n' || c == '\f' // compatible with StringLike#isLineBreak + def stripTrailingPart(s: String) = { + val (pre, post) = s.span(c => !isLineBreak(c)) + pre + post.stripMargin + } + val stripped: List[String] = sc.parts.toList match { + case head :: tail => head.stripMargin :: (tail map stripTrailingPart) + case Nil => Nil + } + new StringContext(stripped: _*).raw(args: _*) + } + } } diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 5e335e240..594f0c013 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -37,7 +37,7 @@ class Definitions { scope.enter(newSymbol(cls, name, flags, TypeBounds.empty)) private def newTypeParam(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) = - newTypeField(cls, name, flags | TypeParamCreationFlags, scope) + newTypeField(cls, name, flags | ClassTypeParamCreationFlags, scope) private def newSyntheticTypeParam(cls: ClassSymbol, scope: MutableScope, paramFlags: FlagSet, suffix: String = "T0") = newTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName | paramFlags, scope) @@ -409,20 +409,20 @@ class Definitions { lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule) - def isTupleType(tp: Type) = { + def isTupleType(tp: Type)(implicit ctx: Context) = { val arity = tp.dealias.argInfos.length arity <= MaxTupleArity && (tp isRef TupleClass(arity)) } - def isProductSubType(tp: Type) = + def isProductSubType(tp: Type)(implicit ctx: Context) = (tp derivesFrom ProductClass) && tp.baseClasses.exists(ProductClasses contains _) - def isFunctionType(tp: Type) = { + def isFunctionType(tp: Type)(implicit ctx: Context) = { val arity = functionArity(tp) 0 <= arity && arity <= MaxFunctionArity && (tp isRef FunctionClass(arity)) } - def functionArity(tp: Type) = tp.dealias.argInfos.length - 1 + def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1 // ----- LambdaXYZ traits ------------------------------------------ @@ -544,7 +544,7 @@ class Definitions { val BooleanEnc = 17 val UnitEnc = 19 - def isValueSubClass(cls1: Symbol, cls2: Symbol) = + def isValueSubClass(cls1: Symbol, cls2: Symbol)(implicit ctx: Context) = valueClassEnc(cls2) % valueClassEnc(cls1) == 0 // ----- Initialization --------------------------------------------------- diff --git a/src/dotty/tools/dotc/core/DenotTransformers.scala b/src/dotty/tools/dotc/core/DenotTransformers.scala index 6daa028fc..e052a07ea 100644 --- a/src/dotty/tools/dotc/core/DenotTransformers.scala +++ b/src/dotty/tools/dotc/core/DenotTransformers.scala @@ -46,4 +46,12 @@ object DenotTransformers { } } } + + /** A `DenotTransformer` trait that has the identity as its `transform` method. + * You might want to inherit from this trait so that new denotations can be + * installed using `installAfter` and `enteredAfter` at the end of the phase. + */ + trait IdentityDenotTransformer extends DenotTransformer { + def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref + } } diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index 264f9aa46..43fff62ec 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -375,7 +375,7 @@ object Denotations { final def signature(implicit ctx: Context): Signature = { if (isType) Signature.NotAMethod // don't force info if this is a type SymDenotation else info match { - case info: SignedType => + case info: MethodicType => try info.signature catch { // !!! DEBUG case ex: Throwable => @@ -494,7 +494,8 @@ object Denotations { } while (d ne denot) initial.syncWithParents case _ => - staleSymbolError + if (coveredInterval.containsPhaseId(ctx.phaseId)) staleSymbolError + else NoDenotation } /** Produce a denotation that is valid for the given context. @@ -512,7 +513,13 @@ object Denotations { def current(implicit ctx: Context): SingleDenotation = { val currentPeriod = ctx.period val valid = myValidFor - assert(valid.code > 0) + if (valid.code <= 0) { + // can happen if we sit on a stale denotation which has been replaced + // wholesale by an installAfter; in this case, proceed to the next + // denotation and try again. + if (validFor == Nowhere && nextInRun.validFor != Nowhere) return nextInRun.current + assert(false) + } if (valid.runId != currentPeriod.runId) bringForward.current else { @@ -551,6 +558,7 @@ object Denotations { cur = next } cur.validFor = Period(currentPeriod.runId, startPid, transformer.lastPhaseId) + //printPeriods(cur) //println(s"new denot: $cur, valid for ${cur.validFor}") } cur.current // multiple transformations could be required @@ -563,23 +571,28 @@ object Denotations { //println(s"searching: $cur at $currentPeriod, valid for ${cur.validFor}") cur = cur.nextInRun cnt += 1 - assert(cnt <= MaxPossiblePhaseId, s"seems to be a loop in Denotations for $this, currentPeriod = $currentPeriod") + assert(cnt <= MaxPossiblePhaseId, demandOutsideDefinedMsg) } cur } - } } + private def demandOutsideDefinedMsg(implicit ctx: Context): String = + s"demanding denotation of $this at phase ${ctx.phase}(${ctx.phaseId}) outside defined interval: defined periods are${definedPeriodsString}" + /** Install this denotation to be the result of the given denotation transformer. * This is the implementation of the same-named method in SymDenotations. * It's placed here because it needs access to private fields of SingleDenotation. + * @pre Can only be called in `phase.next`. */ protected def installAfter(phase: DenotTransformer)(implicit ctx: Context): Unit = { val targetId = phase.next.id assert(ctx.phaseId == targetId, s"denotation update for $this called in phase ${ctx.phase}, expected was ${phase.next}") val current = symbol.current + // println(s"installing $this after $phase/${phase.id}, valid = ${current.validFor}") + // printPeriods(current) this.nextInRun = current.nextInRun this.validFor = Period(ctx.runId, targetId, current.validFor.lastPhaseId) if (current.validFor.firstPhaseId == targetId) { @@ -587,12 +600,14 @@ object Denotations { var prev = current while (prev.nextInRun ne current) prev = prev.nextInRun prev.nextInRun = this + current.validFor = Nowhere } else { // insert this denotation after current current.validFor = Period(ctx.runId, current.validFor.firstPhaseId, targetId - 1) current.nextInRun = this } + // printPeriods(this) } def staleSymbolError(implicit ctx: Context) = { @@ -604,6 +619,22 @@ object Denotations { throw new StaleSymbol(msg) } + /** The period (interval of phases) for which there exists + * a valid denotation in this flock. + */ + def coveredInterval(implicit ctx: Context): Period = { + var cur = this + var cnt = 0 + var interval = validFor + do { + cur = cur.nextInRun + cnt += 1 + assert(cnt <= MaxPossiblePhaseId, demandOutsideDefinedMsg) + interval |= cur.validFor + } while (cur ne this) + interval + } + /** For ClassDenotations only: * If caches influenced by parent classes are still valid, the denotation * itself, otherwise a freshly initialized copy. @@ -614,10 +645,24 @@ object Denotations { if (symbol == NoSymbol) symbol.toString else s"<SingleDenotation of type $infoOrCompleter>" + + def definedPeriodsString: String = { + var sb = new StringBuilder() + var cur = this + var cnt = 0 + do { + sb.append(" " + cur.validFor) + cur = cur.nextInRun + cnt += 1 + if (cnt > MaxPossiblePhaseId) { sb.append(" ..."); cur = this } + } while (cur ne this) + sb.toString + } + // ------ PreDenotation ops ---------------------------------------------- final def first = this - final def toDenot(pre: Type)(implicit ctx: Context) = this + final def toDenot(pre: Type)(implicit ctx: Context): Denotation = this final def containsSym(sym: Symbol): Boolean = hasUniqueSym && (symbol eq sym) final def containsSig(sig: Signature)(implicit ctx: Context) = exists && (signature matches sig) @@ -764,7 +809,7 @@ object Denotations { else DenotUnion(this, that) } - case class DenotUnion(denots1: PreDenotation, denots2: PreDenotation) extends PreDenotation { + final case class DenotUnion(denots1: PreDenotation, denots2: PreDenotation) extends PreDenotation { assert(denots1.exists && denots2.exists, s"Union of non-existing denotations ($denots1) and ($denots2)") def exists = true def first = denots1.first diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index 40da7525d..c467a553f 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -102,8 +102,16 @@ object Flags { } /** The list of non-empty names of flags that are set in this FlagSet */ - def flagStrings: Seq[String] = - (2 to MaxFlag).flatMap(flagString) + def flagStrings: Seq[String] = { + val rawStrings = (2 to MaxFlag).flatMap(flagString) + if (this is Local) + rawStrings.filter(_ != "<local>").map { + case "private" => "private[this]" + case "protected" => "protected[this]" + case str => str + } + else rawStrings + } /** The string representation of this flag set */ override def toString = flagStrings.mkString(" ") @@ -316,8 +324,8 @@ object Flags { /** Symbol is initialized to the default value, e.g. var x: T = _ */ final val DefaultInit = termFlag(29, "<defaultinit>") - /** Symbol is a macro */ - final val Macro = commonFlag(30, "<macro>") + /** Symbol is inlined */ + final val Inline = commonFlag(30, "inline") /** Symbol is defined by a Java class */ final val JavaDefined = commonFlag(31, "<java>") @@ -387,14 +395,17 @@ object Flags { /** A definition that's initialized before the super call (Scala 2.x only) */ final val Scala2PreSuper = termFlag(58, "<presuper>") + /** A macro (Scala 2.x only) */ + final val Macro = commonFlag(59, "<macro>") + /** A method that is known to have inherited default parameters */ - final val InheritedDefaultParams = termFlag(59, "<inherited-default-param>") + final val InheritedDefaultParams = termFlag(60, "<inherited-default-param>") - /** A method that is known to no default parameters */ - final val NoDefaultParams = termFlag(60, "<no-default-param>") + /** A method that is known to have no default parameters */ + final val NoDefaultParams = termFlag(61, "<no-default-param>") /** A denotation that is valid in all run-ids */ - final val Permanent = commonFlag(61, "<permanent>") + final val Permanent = commonFlag(62, "<permanent>") // --------- Combined Flag Sets and Conjunctions ---------------------- @@ -405,7 +416,10 @@ object Flags { /** Flags representing modifiers that can appear in trees */ final val ModifierFlags = - SourceModifierFlags | Trait | Module | Param | Synthetic | Package + SourceModifierFlags | Module | Param | Synthetic | Package | Local + // | Trait is subsumed by commonFlags(Lazy) from SourceModifierFlags + + assert(ModifierFlags.isTermFlags && ModifierFlags.isTypeFlags) /** Flags representing access rights */ final val AccessFlags = Private | Protected | Local @@ -438,8 +452,8 @@ object Flags { /** The flags of the self symbol */ final val SelfSymFlags = Private | Local | Deferred - /** The flags of a type parameter */ - final val TypeParamCreationFlags = TypeParam | Deferred | Protected | Local + /** The flags of a class type parameter */ + final def ClassTypeParamCreationFlags = TypeParam | Deferred | Protected | Local /** Flags that can apply to both a module val and a module class, except those that * are added at creation anyway diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala index 5bdafcf8a..404a0844a 100644 --- a/src/dotty/tools/dotc/core/NameOps.scala +++ b/src/dotty/tools/dotc/core/NameOps.scala @@ -47,6 +47,13 @@ object NameOps { } } + object SuperAccessorName { + val pre = nme.SUPER_PREFIX + def apply(name: TermName): TermName = pre ++ name + def unapply(name: TermName): Option[TermName] = + if (name startsWith pre) Some(name.drop(pre.length).asTermName) else None + } + implicit class NameDecorator[N <: Name](val name: N) extends AnyVal { import nme._ @@ -59,7 +66,6 @@ object NameOps { def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX def isLoopHeaderLabel = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX) def isProtectedAccessorName = name startsWith PROTECTED_PREFIX - def isSuperAccessorName = name startsWith SUPER_PREFIX def isReplWrapperName = name containsSlice INTERPRETER_IMPORT_WRAPPER def isSetterName = name endsWith SETTER_SUFFIX def isTraitSetterName = isSetterName && (name containsSlice TRAIT_SETTER_SEPARATOR) @@ -126,6 +132,9 @@ object NameOps { if (flags is (ModuleClass, butNot = Package)) name.asTypeName.moduleClassName.asInstanceOf[N] else name + /** The superaccessor for method with given name */ + def superName: TermName = (nme.SUPER_PREFIX ++ name).toTermName + /** The expanded name of `name` relative to this class `base` with given `separator` */ def expandedName(base: Symbol, separator: Name = nme.EXPAND_SEPARATOR)(implicit ctx: Context): N = { @@ -247,17 +256,13 @@ object NameOps { else -1 } - /** The name of a super-accessor */ - def superAccessorName: TermName = - SUPER_PREFIX ++ name - /** The name of an accessor for protected symbols. */ def protectedAccessorName: TermName = - PROTECTED_PREFIX ++ name + PROTECTED_PREFIX ++ name.unexpandedName() /** The name of a setter for protected symbols. Used for inherited Java fields. */ - def protectedSetterName(name: Name): TermName = - PROTECTED_SET_PREFIX ++ name + def protectedSetterName: TermName = + PROTECTED_SET_PREFIX ++ name.unexpandedName() def moduleVarName: TermName = name ++ MODULE_VAR_SUFFIX diff --git a/src/dotty/tools/dotc/core/Periods.scala b/src/dotty/tools/dotc/core/Periods.scala index 4ab04fad0..e0d9e3b5d 100644 --- a/src/dotty/tools/dotc/core/Periods.scala +++ b/src/dotty/tools/dotc/core/Periods.scala @@ -67,6 +67,8 @@ object Periods { /** The first phase of this period */ def firstPhaseId = lastPhaseId - (code & PhaseMask) + def containsPhaseId(id: PhaseId) = firstPhaseId <= id && id <= lastPhaseId + /** Does this period contain given period? */ def contains(that: Period): Boolean = { // Let this = (r1, l1, d1), that = (r2, l2, d2) @@ -106,6 +108,11 @@ object Periods { else Nowhere + def | (that: Period): Period = + Period(this.runId, + this.firstPhaseId min that.firstPhaseId, + this.lastPhaseId max that.lastPhaseId) + override def toString = s"Period($firstPhaseId..$lastPhaseId, run = $runId)" } diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala index 7bc5f3052..aabde4cf9 100644 --- a/src/dotty/tools/dotc/core/Phases.scala +++ b/src/dotty/tools/dotc/core/Phases.scala @@ -9,7 +9,6 @@ import Denotations._ import config.Printers._ import scala.collection.mutable.{ListBuffer, ArrayBuffer} import dotty.tools.dotc.transform.TreeTransforms.{TreeTransformer, TreeTransform} -import dotty.tools.dotc.transform.PostTyperTransformers.PostTyperTransformer import dotty.tools.dotc.transform.TreeTransforms import TreeTransforms.Separator import Periods._ @@ -72,12 +71,10 @@ object Phases { /** Squash TreeTransform's beloning to same sublist to a single TreeTransformer * Each TreeTransform gets own period, * whereas a combined TreeTransformer gets period equal to union of periods of it's TreeTransforms - * first TreeTransformer emitted is PostTyperTransformer that simplifies trees, see it's documentation */ private def squashPhases(phasess: List[List[Phase]]): Array[Phase] = { val squashedPhases = ListBuffer[Phase]() var prevPhases: Set[String] = Set.empty - var postTyperEmmited = false var i = 0 while (i < phasess.length) { if (phasess(i).length > 1) { @@ -95,17 +92,10 @@ object Phases { } } val transforms = phasess(i).asInstanceOf[List[TreeTransform]] - val block = - if (!postTyperEmmited) { - postTyperEmmited = true - new PostTyperTransformer { - override def name: String = transformations.map(_.name).mkString("TreeTransform:{", ", ", "}") - override def transformations: Array[TreeTransform] = transforms.toArray - } - } else new TreeTransformer { - override def name: String = transformations.map(_.name).mkString("TreeTransform:{", ", ", "}") - override def transformations: Array[TreeTransform] = transforms.toArray - } + val block = new TreeTransformer { + override def name: String = transformations.map(_.name).mkString("TreeTransform:{", ", ", "}") + override def transformations: Array[TreeTransform] = transforms.toArray + } squashedPhases += block prevPhases ++= phasess(i).map(_.name) block.init(this, phasess(i).head.id, phasess(i).last.id) diff --git a/src/dotty/tools/dotc/core/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala index 367713d11..919e35a7e 100644 --- a/src/dotty/tools/dotc/core/Scopes.scala +++ b/src/dotty/tools/dotc/core/Scopes.scala @@ -18,6 +18,7 @@ import SymDenotations._ import printing.Texts._ import printing.Printer import util.common._ +import util.DotClass import SymDenotations.NoDenotation import collection.mutable.ListBuffer @@ -55,7 +56,7 @@ object Scopes { * or to delete them. These methods are provided by subclass * MutableScope. */ - abstract class Scope extends printing.Showable with Iterable[Symbol] { + abstract class Scope extends DotClass with printing.Showable with Iterable[Symbol] { /** The last scope-entry from which all others are reachable via `prev` */ private[dotc] def lastEntry: ScopeEntry @@ -77,8 +78,8 @@ object Scopes { */ def iterator: Iterator[Symbol] = toList.iterator - /** Returns a new scope with the same content as this one. */ - def cloneScope(implicit ctx: Context): Scope + /** Returns a new mutable scope with the same content as this one. */ + def cloneScope(implicit ctx: Context): MutableScope /** Is the scope empty? */ override def isEmpty: Boolean = lastEntry eq null @@ -354,7 +355,7 @@ object Scopes { override def size = 0 override def nestingLevel = 0 override def toList = Nil - override def cloneScope(implicit ctx: Context): Scope = this + override def cloneScope(implicit ctx: Context): MutableScope = unsupported("cloneScope") override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = null override def lookupNextEntry(entry: ScopeEntry)(implicit ctx: Context): ScopeEntry = null } diff --git a/src/dotty/tools/dotc/core/Signature.scala b/src/dotty/tools/dotc/core/Signature.scala index eb85fbb99..22d038d11 100644 --- a/src/dotty/tools/dotc/core/Signature.scala +++ b/src/dotty/tools/dotc/core/Signature.scala @@ -49,7 +49,7 @@ object Signature { * a type different from PolyType, MethodType, or ExprType. */ val NotAMethod = Signature(List(), EmptyTypeName) - + /** The signature of an overloaded denotation. */ val OverloadedSignature = Signature(List(tpnme.OVERLOADED), EmptyTypeName) diff --git a/src/dotty/tools/dotc/core/Substituters.scala b/src/dotty/tools/dotc/core/Substituters.scala index 1b96de47e..3d14317cb 100644 --- a/src/dotty/tools/dotc/core/Substituters.scala +++ b/src/dotty/tools/dotc/core/Substituters.scala @@ -205,7 +205,11 @@ trait Substituters { this: Context => final class SubstMap(from: List[Symbol], to: List[Type]) extends DeepTypeMap { def apply(tp: Type): Type = subst(tp, from, to, this) } - +/* not needed yet + final class SubstDealiasMap(from: List[Symbol], to: List[Type]) extends SubstMap(from, to) { + override def apply(tp: Type): Type = subst(tp.dealias, from, to, this) + } +*/ final class SubstSymMap(from: List[Symbol], to: List[Symbol]) extends DeepTypeMap { def apply(tp: Type): Type = substSym(tp, from, to, this) } diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 802762045..b0a09baf0 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -83,6 +83,9 @@ object SymDenotations { /** The owner of the symbol; overridden in NoDenotation */ def owner: Symbol = ownerIfExists + /** Same as owner, except returns NoSymbol for NoSymbol */ + def maybeOwner: Symbol = if (exists) owner else NoSymbol + /** The flag set */ final def flags(implicit ctx: Context): FlagSet = { ensureCompleted(); myFlags } @@ -212,6 +215,14 @@ object SymDenotations { final def addAnnotation(annot: Annotation): Unit = annotations = annot :: myAnnotations + /** Remove annotation with given class from this denotation */ + final def removeAnnotation(cls: Symbol)(implicit ctx: Context): Unit = + annotations = myAnnotations.filterNot(_ matches cls) + + /** Copy all annotations from given symbol by adding them to this symbol */ + final def addAnnotations(from: Symbol)(implicit ctx: Context): Unit = + from.annotations.foreach(addAnnotation) + @tailrec private def dropOtherAnnotations(anns: List[Annotation], cls: Symbol)(implicit ctx: Context): List[Annotation] = anns match { case ann :: rest => if (ann matches cls) anns else dropOtherAnnotations(rest, cls) @@ -321,6 +332,12 @@ object SymDenotations { final def isAnonymousClass(implicit ctx: Context): Boolean = initial.asSymDenotation.name startsWith tpnme.ANON_CLASS + /** Is symbol a primitive value class? */ + def isPrimitiveValueClass(implicit ctx: Context) = defn.ScalaValueClasses contains symbol + + /** Is symbol a phantom class for which no runtime representation exists? */ + def isPhantomClass(implicit ctx: Context) = defn.PhantomClasses contains symbol + /** Is this symbol a class representing a refinement? These classes * are used only temporarily in Typer and Unpickler as an intermediate * step for creating Refinement types. @@ -447,7 +464,7 @@ object SymDenotations { def accessWithin(boundary: Symbol) = ctx.owner.isContainedIn(boundary) && (!(this is JavaDefined) || // disregard package nesting for Java - ctx.owner.enclosingPackage == boundary.enclosingPackage) + ctx.owner.enclosingPackageClass == boundary.enclosingPackageClass) /** Are we within definition of linked class of `boundary`? */ def accessWithinLinked(boundary: Symbol) = { @@ -572,6 +589,12 @@ object SymDenotations { NoSymbol } + /** The field accessed by this getter or setter */ + def accessedField(implicit ctx: Context): Symbol = { + val fieldName = if (isSetter) name.asTermName.setterToGetter else name + owner.info.decl(fieldName).suchThat(d => !(d is Method)).symbol + } + /** The chain of owners of this denotation, starting with the denoting symbol itself */ final def ownersIterator(implicit ctx: Context) = new Iterator[Symbol] { private[this] var current = symbol @@ -624,8 +647,8 @@ object SymDenotations { } /** The package class containing this denotation */ - final def enclosingPackage(implicit ctx: Context): Symbol = - if (this is PackageClass) symbol else owner.enclosingPackage + final def enclosingPackageClass(implicit ctx: Context): Symbol = + if (this is PackageClass) symbol else owner.enclosingPackageClass /** The module object with the same (term-) name as this class or module class, * and which is also defined in the same scope and compilation unit. @@ -747,7 +770,6 @@ object SymDenotations { loop(base.info.baseClasses.dropWhile(owner != _).tail) } - /** A a member of class `base` is incomplete if * (1) it is declared deferred or * (2) it is abstract override and its super symbol in `base` is @@ -809,6 +831,11 @@ object SymDenotations { else if (this is Contravariant) -1 else 0 + /** The flags to be used for a type parameter owned by this symbol. + * Overridden by ClassDenotation. + */ + def typeParamCreationFlags: FlagSet = TypeParam + override def toString = { val kindString = if (myFlags is ModuleClass) "module class" @@ -848,6 +875,22 @@ object SymDenotations { /** Install this denotation as the result of the given denotation transformer. */ override def installAfter(phase: DenotTransformer)(implicit ctx: Context): Unit = super.installAfter(phase) + + /** Remove private modifier from symbol's definition. If this symbol + * is not a constructor nor a static module, rename it by expanding its name to avoid name clashes + * @param base the fully qualified name of this class will be appended if name expansion is needed + */ + final def makeNotPrivateAfter(base: Symbol, phase: DenotTransformer)(implicit ctx: Context): Unit = { + if (this.is(Private)) { + val newName = + if (this.is(Module) && isStatic || isClassConstructor) name + else { + if (this.is(Module)) moduleClass.makeNotPrivateAfter(base, phase) + name.expandedName(base) + } + copySymDenotation(name = newName, initFlags = flags &~ Private).installAfter(phase) + } + } } /** The contents of a class definition during a period @@ -895,6 +938,15 @@ object SymDenotations { case _ => Nil } + /** The symbol of the superclass, NoSymbol if no superclass exists */ + def superClass(implicit ctx: Context): Symbol = classParents match { + case parent :: _ => + val cls = parent.classSymbol + if (cls is Trait) NoSymbol else cls + case _ => + NoSymbol + } + /** The denotation is fully completed: all attributes are fully defined. * ClassDenotations compiled from source are first completed, then fully completed. * @see Namer#ClassCompleter @@ -938,6 +990,7 @@ object SymDenotations { mySuperClassBits = null myMemberFingerPrint = FingerPrint.unknown myMemberCache = null + myMemberCachePeriod = Nowhere memberNamesCache = SimpleMap.Empty } @@ -1036,6 +1089,8 @@ object SymDenotations { (symbol eq defn.NothingClass) || (symbol eq defn.NullClass) && (base ne defn.NothingClass)) + final override def typeParamCreationFlags = ClassTypeParamCreationFlags + private[this] var myMemberFingerPrint: FingerPrint = FingerPrint.unknown private def computeMemberFingerPrint(implicit ctx: Context): FingerPrint = { @@ -1070,9 +1125,13 @@ object SymDenotations { } private[this] var myMemberCache: LRUCache[Name, PreDenotation] = null + private[this] var myMemberCachePeriod: Period = Nowhere - private def memberCache: LRUCache[Name, PreDenotation] = { - if (myMemberCache == null) myMemberCache = new LRUCache + private def memberCache(implicit ctx: Context): LRUCache[Name, PreDenotation] = { + if (myMemberCachePeriod != ctx.period) { + myMemberCache = new LRUCache + myMemberCachePeriod = ctx.period + } myMemberCache } @@ -1289,9 +1348,20 @@ object SymDenotations { decls.denotsNamed(cname).first.symbol } - def underlyingOfValueClass: Type = ??? - - def valueClassUnbox: Symbol = ??? + /** If this class has the same `decls` scope reference in `phase` and + * `phase.next`, install a new denotation with a cloned scope in `phase.next`. + * @pre Can only be called in `phase.next`. + */ + def ensureFreshScopeAfter(phase: DenotTransformer)(implicit ctx: Context): Unit = { + assert(ctx.phaseId == phase.next.id) + val prevCtx = ctx.withPhase(phase) + val ClassInfo(pre, _, ps, decls, selfInfo) = classInfo + if (classInfo(prevCtx).decls eq decls) { + copySymDenotation( + info = ClassInfo(pre, classSymbol, ps, decls.cloneScope, selfInfo), + initFlags = this.flags &~ Frozen).installAfter(phase) + } + } } /** The denotation of a package class. diff --git a/src/dotty/tools/dotc/core/SymbolLoaders.scala b/src/dotty/tools/dotc/core/SymbolLoaders.scala index bebad60cc..886c728b7 100644 --- a/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -12,7 +12,7 @@ import scala.compat.Platform.currentTime import dotty.tools.io.{ ClassPath, AbstractFile } import Contexts._, Symbols._, Flags._, SymDenotations._, Types._, Scopes._, util.Positions._, Names._ import StdNames._, NameOps._ -import Decorators.StringDecorator +import Decorators.{StringDecorator, StringInterpolators} import pickling.ClassfileParser object SymbolLoaders { @@ -69,8 +69,8 @@ class SymbolLoaders { // require yjp.jar at runtime. See SI-2089. if (ctx.settings.termConflict.isDefault) throw new TypeError( - s"""$owner contains object and package with same name: $pname - |one of them needs to be removed from classpath""".stripMargin) + sm"""$owner contains object and package with same name: $pname + |one of them needs to be removed from classpath""") else if (ctx.settings.termConflict.value == "package") { ctx.warning( s"Resolving package/object name conflict in favor of package ${preExisting.fullName}. The object will be inaccessible.") diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index 26553ddff..1767d7c0c 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -16,6 +16,7 @@ import printing.Printer import Types._ import Annotations._ import util.Positions._ +import DenotTransformers._ import StdNames._ import NameOps._ import ast.tpd.{TreeTypeMap, Tree} @@ -250,7 +251,7 @@ trait Symbols { this: Context => val tparams = tparamBuf.toList val bounds = boundsFn(trefBuf.toList) for ((name, tparam, bound) <- (names, tparams, bounds).zipped) - tparam.denot = SymDenotation(tparam, owner, name, flags | TypeParamCreationFlags, bound) + tparam.denot = SymDenotation(tparam, owner, name, flags | owner.typeParamCreationFlags, bound) tparams } @@ -260,16 +261,14 @@ trait Symbols { this: Context => newSymbol(owner, name, SyntheticArtifact, if (name.isTypeName) TypeAlias(ErrorType) else ErrorType) - type OwnerMap = Symbol => Symbol - /** Map given symbols, subjecting all types to given type map and owner map. * Cross symbol references are brought over from originals to copies. * Do not copy any symbols if all attributes of all symbols stay the same. */ def mapSymbols( originals: List[Symbol], - typeMap: TypeMap = IdentityTypeMap, - ownerMap: OwnerMap = identity) + typeMap: Type => Type = IdentityTypeMap, + ownerMap: Symbol => Symbol = identity) = if (originals forall (sym => (typeMap(sym.info) eq sym.info) && (ownerMap(sym.owner) eq sym.owner))) @@ -358,6 +357,10 @@ object Symbols { final def asType(implicit ctx: Context): TypeSymbol = { assert(isType, s"isType called on not-a-Type $this"); asInstanceOf[TypeSymbol] } final def asClass: ClassSymbol = asInstanceOf[ClassSymbol] + /** Special cased here, because it may be used on naked symbols in substituters */ + final def isStatic(implicit ctx: Context): Boolean = + lastDenot != null && denot.isStatic + /** 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. @@ -372,6 +375,17 @@ object Symbols { this } + /** Enter this symbol in its class owner after given `phase`. Create a fresh + * denotation for its owner class if the class has not yet already one + * that starts being valid after `phase`. + * @pre Symbol is a class member + */ + def enteredAfter(phase: DenotTransformer)(implicit ctx: Context): this.type = { + val nextCtx = ctx.withPhase(phase.next) + this.owner.asClass.ensureFreshScopeAfter(phase)(nextCtx) + entered(nextCtx) + } + /** This symbol, if it exists, otherwise the result of evaluating `that` */ def orElse(that: => Symbol)(implicit ctx: Context) = if (this.exists) this else that @@ -381,14 +395,8 @@ object Symbols { /** Is this symbol a user-defined value class? */ final def isDerivedValueClass(implicit ctx: Context): Boolean = - false && // value classes are not supported yet - isClass && denot.derivesFrom(defn.AnyValClass) && !isPrimitiveValueClass - - /** Is symbol a primitive value class? */ - def isPrimitiveValueClass(implicit ctx: Context) = defn.ScalaValueClasses contains this - - /** Is symbol a phantom class for which no runtime representation exists? */ - def isPhantomClass(implicit ctx: Context) = defn.PhantomClasses contains this + false // will migrate to ValueClasses.isDerivedValueClass; + // unsupported value class code will continue to use this stub while it exists /** The current name of this symbol */ final def name(implicit ctx: Context): ThisName = denot.name.asInstanceOf[ThisName] diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 4885b30d8..289515ae1 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -813,11 +813,15 @@ object Types { if (from1.isEmpty) ctx.subst1(this, from.head, to.head, null) else { val from2 = from1.tail - if (from2.isEmpty) ctx.subst2(this, from.head, to.head, from.tail.head, to.tail.head, null) + if (from2.isEmpty) ctx.subst2(this, from.head, to.head, from1.head, to.tail.head, null) else ctx.subst(this, from, to, null) } } +/* Not needed yet: + final def substDealias(from: List[Symbol], to: List[Type])(implicit ctx: Context): Type = + new ctx.SubstDealiasMap(from, to).apply(this) +*/ /** Substitute all types of the form `PolyParam(from, N)` by * `PolyParam(to, N)`. */ @@ -1602,17 +1606,22 @@ object Types { // and therefore two different poly types would never be equal. /** A trait that mixes in functionality for signature caching */ - trait SignedType extends Type { + trait MethodicType extends Type { private[this] var mySignature: Signature = _ private[this] var mySignatureRunId: Int = NoRunId protected def computeSignature(implicit ctx: Context): Signature - protected def resultSignature(implicit ctx: Context) = resultType match { - case rtp: SignedType => rtp.signature + protected def resultSignature(implicit ctx: Context) = try resultType match { + case rtp: MethodicType => rtp.signature case tp => Signature(tp, isJava = false) } + catch { + case ex: AssertionError => + println(i"failure while taking result signture of $resultType") + throw ex + } final override def signature(implicit ctx: Context): Signature = { if (ctx.runId != mySignatureRunId) { @@ -1623,7 +1632,7 @@ object Types { } } - trait MethodOrPoly extends SignedType + trait MethodOrPoly extends MethodicType abstract case class MethodType(paramNames: List[TermName], paramTypes: List[Type]) (resultTypeExp: MethodType => Type) @@ -1717,6 +1726,8 @@ object Types { def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType def apply(paramNames: List[TermName], paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType = apply(paramNames, paramTypes)(_ => resultType) + def apply(paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType = + apply(nme.syntheticParamNames(paramTypes.length), paramTypes)(resultTypeExp) def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType = apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType) def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = { @@ -1748,7 +1759,7 @@ object Types { } abstract case class ExprType(override val resultType: Type) - extends CachedProxyType with TermType with SignedType { + extends CachedProxyType with TermType with MethodicType { override def underlying(implicit ctx: Context): Type = resultType protected def computeSignature(implicit ctx: Context): Signature = resultSignature def derivedExprType(resultType: Type)(implicit ctx: Context) = @@ -2019,19 +2030,31 @@ object Types { decls: Scope, selfInfo: DotClass /* should be: Type | Symbol */) extends CachedGroundType with TypeType { - def selfType(implicit ctx: Context): Type = selfInfo match { - case NoType => - if (selfTypeCache == null) selfTypeCache = computeSelfType(cls.typeRef, cls.typeParams) - selfTypeCache - case tp: Type => tp - case self: Symbol => self.info + /** The self type of a class is the conjunction of + * - the explicit self type if given (or the info of a given self symbol), and + * - the fully applied reference to the class itself. + */ + def selfType(implicit ctx: Context): Type = { + if (selfTypeCache == null) { + def fullRef = fullyAppliedRef(cls.typeRef, cls.typeParams) + selfTypeCache = selfInfo match { + case NoType => + fullRef + case tp: Type => + if (cls is Module) tp else AndType(tp, fullRef) + case self: Symbol => + assert(!(cls is Module)) + AndType(self.info, fullRef) + } + } + selfTypeCache } private var selfTypeCache: Type = null - private def computeSelfType(base: Type, tparams: List[TypeSymbol])(implicit ctx: Context): Type = tparams match { + private def fullyAppliedRef(base: Type, tparams: List[TypeSymbol])(implicit ctx: Context): Type = tparams match { case tparam :: tparams1 => - computeSelfType( + fullyAppliedRef( RefinedType(base, tparam.name, TypeRef(cls.thisType, tparam).toBounds(tparam)), tparams1) case nil => @@ -2077,8 +2100,8 @@ object Types { if (prefix eq this.prefix) this else ClassInfo(prefix, cls, classParents, decls, selfInfo) - def derivedClassInfo(prefix: Type = this.prefix, classParents: List[TypeRef] = classParents, selfInfo: DotClass = this.selfInfo)(implicit ctx: Context) = - if ((prefix eq this.prefix) && (classParents eq this.classParents) && (selfInfo eq this.selfInfo)) this + def derivedClassInfo(prefix: Type = this.prefix, classParents: List[TypeRef] = classParents, decls: Scope = this.decls, selfInfo: DotClass = this.selfInfo)(implicit ctx: Context) = + if ((prefix eq this.prefix) && (classParents eq this.classParents) && (decls eq this.decls) && (selfInfo eq this.selfInfo)) this else ClassInfo(prefix, cls, classParents, decls, selfInfo) override def computeHash = doHash(cls, prefix) @@ -2431,7 +2454,7 @@ object Types { case self: Type => this(self) case _ => tp.self } - tp.derivedClassInfo(prefix1, parents1, self1) + tp.derivedClassInfo(prefix1, parents1, tp.decls, self1) } } diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index 0ed301732..59658c9c1 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -48,8 +48,8 @@ class ClassfileParser( case e: RuntimeException => if (ctx.debug) e.printStackTrace() throw new IOException( - s"""class file $classfile is broken, reading aborted with $e.getClass - |${Option(e.getMessage).getOrElse("")}""".stripMargin) + sm"""class file $classfile is broken, reading aborted with $e.getClass + |${Option(e.getMessage).getOrElse("")}""") } private def parseHeader(): Unit = { @@ -353,7 +353,7 @@ class ClassfileParser( val tpname = subName(':'.==).toTypeName val expname = if (owner.isClass) tpname.expandedName(owner) else tpname val s = ctx.newSymbol( - owner, expname, Flags.TypeParamCreationFlags, + owner, expname, owner.typeParamCreationFlags, typeParamCompleter(index), coord = indexCoord(index)) if (owner.isClass) owner.asClass.enter(s, owner.decls) tparams = tparams + (tpname -> s) @@ -702,12 +702,12 @@ class ClassfileParser( getMember(owner, innerName.toTypeName) } assert(result ne NoSymbol, - s"""failure to resolve inner class: - |externalName = $externalName, - |outerName = $outerName, - |innerName = $innerName - |owner.fullName = owner.showFullName - |while parsing ${classfile}""".stripMargin) + sm"""failure to resolve inner class: + |externalName = $externalName, + |outerName = $outerName, + |innerName = $innerName + |owner.fullName = owner.showFullName + |while parsing ${classfile}""") result case None => @@ -752,7 +752,7 @@ class ClassfileParser( private def setPrivateWithin(denot: SymDenotation, jflags: Int)(implicit ctx: Context): Unit = { if ((jflags & (JAVA_ACC_PRIVATE | JAVA_ACC_PUBLIC)) == 0) - denot.privateWithin = denot.enclosingPackage + denot.privateWithin = denot.enclosingPackageClass } private def isPrivate(flags: Int) = (flags & JAVA_ACC_PRIVATE) != 0 diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index dd26b20df..36b2c99bf 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -53,10 +53,10 @@ object UnPickler { val result = restpe.parameterizeWith(tparams) for ((msg, pos) <- err) ctx.warning( - s"""$msg - |originally parsed type : ${tp.show} - |will be approximated by: ${result.show}. - |Proceed at own risk.""".stripMargin) + sm"""$msg + |originally parsed type : ${tp.show} + |will be approximated by: ${result.show}. + |Proceed at own risk.""") result } else @@ -161,8 +161,8 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: protected def errorBadSignature(msg: String, original: Option[RuntimeException] = None)(implicit ctx: Context) = { val ex = new BadSignature( - s"""error reading Scala signature of $classRoot from $source: - |error occured at position $readIndex: $msg""".stripMargin) + sm"""error reading Scala signature of $classRoot from $source: + |error occured at position $readIndex: $msg""") /*if (debug)*/ original.getOrElse(ex).printStackTrace() // !!! DEBUG throw ex } @@ -453,7 +453,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: var flags1 = flags if (flags is TypeParam) { name1 = name1.expandedName(owner) - flags1 |= TypeParamCreationFlags | ExpandedName + flags1 |= owner.typeParamCreationFlags | ExpandedName } ctx.newSymbol(owner, name1, flags1, localMemberUnpickler, coord = start) case CLASSsym => @@ -1080,7 +1080,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: setSym() val qualifier = readTreeRef() val selector = readNameRef() - Select(qualifier, symbol.namedType) + qualifier.select(symbol.namedType) case IDENTtree => setSymName() Ident(symbol.namedType) diff --git a/src/dotty/tools/dotc/core/transform/Erasure.scala b/src/dotty/tools/dotc/core/transform/Erasure.scala index da14f72d1..e35cdd128 100644 --- a/src/dotty/tools/dotc/core/transform/Erasure.scala +++ b/src/dotty/tools/dotc/core/transform/Erasure.scala @@ -146,7 +146,7 @@ class Erasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wildcard if ((cls eq defn.ObjectClass) || cls.isPrimitiveValueClass) Nil else if (cls eq defn.ArrayClass) defn.ObjectClass.typeRef :: Nil else removeLaterObjects(classParents.mapConserve(eraseTypeRef)) - tp.derivedClassInfo(this(pre), parents, this(tp.selfType)) + tp.derivedClassInfo(this(pre), parents, decls, this(tp.selfType)) case NoType | NoPrefix | ErrorType => tp case tp: WildcardType if wildcardOK => |