diff options
author | Adriaan Moors <adriaan@lightbend.com> | 2016-08-11 16:59:19 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-08-11 16:59:19 -0700 |
commit | fdb3105228db20e347a61e61e2e1d86b27683d0d (patch) | |
tree | 3acf954c38584c945cefcf63292e07a2b864f2bc /src/reflect/scala/reflect | |
parent | 19aea1a52e941977691892e0ebd52e078fe5f9cc (diff) | |
parent | af02e291b6baf4f673a79f4c32e6da67d31bdd75 (diff) | |
download | scala-fdb3105228db20e347a61e61e2e1d86b27683d0d.tar.gz scala-fdb3105228db20e347a61e61e2e1d86b27683d0d.tar.bz2 scala-fdb3105228db20e347a61e61e2e1d86b27683d0d.zip |
Merge pull request #5141 from adriaanm/fields
Introducing: the fields phase [ci: last-only]
Diffstat (limited to 'src/reflect/scala/reflect')
16 files changed, 170 insertions, 216 deletions
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index fa19103d0c..cfde164754 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -175,15 +175,6 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => case (Nil, defaults) => defaults contains category case (metas, _) => metas exists (_ matches category) } - - def mkFilter(categories: List[Symbol], defaultRetention: Boolean)(ann: AnnotationInfo) = - (ann.metaAnnotations, ann.defaultTargets) match { - case (Nil, Nil) => defaultRetention - case (Nil, defaults) => categories exists defaults.contains - case (metas, _) => - val metaSyms = metas collect { case ann if !ann.symbol.isInstanceOf[StubSymbol] => ann.symbol } - categories exists (category => metaSyms exists (_ isNonBottomSubClass category)) - } } class CompleteAnnotationInfo( @@ -305,10 +296,13 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => } /** The default kind of members to which this annotation is attached. - * For instance, for scala.deprecated defaultTargets = - * List(getter, setter, beanGetter, beanSetter). - */ - def defaultTargets = symbol.annotations map (_.symbol) filter isMetaAnnotation + * For instance, for scala.deprecated defaultTargets = + * List(getter, setter, beanGetter, beanSetter). + * + * NOTE: have to call symbol.initialize, since we won't get any annotations if the symbol hasn't yet been completed + */ + def defaultTargets = symbol.initialize.annotations map (_.symbol) filter isMetaAnnotation + // Test whether the typeSymbol of atp conforms to the given class. def matches(clazz: Symbol) = !symbol.isInstanceOf[StubSymbol] && (symbol isNonBottomSubClass clazz) // All subtrees of all args are considered. diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 0342daf113..eca1bbea5a 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -362,7 +362,6 @@ trait Definitions extends api.StandardDefinitions { // classes with special meanings lazy val StringAddClass = requiredClass[scala.runtime.StringAdd] lazy val ScalaNumberClass = requiredClass[scala.math.ScalaNumber] - lazy val TraitSetterAnnotationClass = requiredClass[scala.runtime.TraitSetter] lazy val DelayedInitClass = requiredClass[scala.DelayedInit] def delayedInitMethod = getMemberMethod(DelayedInitClass, nme.delayedInit) @@ -675,8 +674,10 @@ trait Definitions extends api.StandardDefinitions { // Note that these call .dealiasWiden and not .normalize, the latter of which // tends to change the course of events by forcing types. def isFunctionType(tp: Type) = isFunctionTypeDirect(tp.dealiasWiden) + // the number of arguments expected by the function described by `tp` (a FunctionN or SAM type), // or `-1` if `tp` does not represent a function type or SAM + // for use during typers (after fields, samOf will be confused by abstract accessors for trait fields) def functionArityFromType(tp: Type) = { val dealiased = tp.dealiasWiden if (isFunctionTypeDirect(dealiased)) dealiased.typeArgs.length - 1 @@ -686,16 +687,6 @@ trait Definitions extends api.StandardDefinitions { } } - // the result type of a function or corresponding SAM type - def functionResultType(tp: Type): Type = { - val dealiased = tp.dealiasWiden - if (isFunctionTypeDirect(dealiased)) dealiased.typeArgs.last - else samOf(tp) match { - case samSym if samSym.exists => tp.memberInfo(samSym).resultType.deconst - case _ => NoType - } - } - // the SAM's parameters and the Function's formals must have the same length // (varargs etc don't come into play, as we're comparing signatures, not checking an application) def samMatchesFunctionBasedOnArity(sam: Symbol, formals: List[Any]): Boolean = @@ -1049,11 +1040,7 @@ trait Definitions extends api.StandardDefinitions { } } - /** Remove references to class Object (other than the head) in a list of parents */ - def removeLaterObjects(tps: List[Type]): List[Type] = tps match { - case Nil => Nil - case x :: xs => x :: xs.filterNot(_.typeSymbol == ObjectClass) - } + /** Remove all but one reference to class Object from a list of parents. */ def removeRedundantObjects(tps: List[Type]): List[Type] = tps match { case Nil => Nil @@ -1470,6 +1457,7 @@ trait Definitions extends api.StandardDefinitions { lazy val StringAdd_+ = getMemberMethod(StringAddClass, nme.PLUS) // The given symbol represents either String.+ or StringAdd.+ + // TODO: this misses Predef.any2stringadd def isStringAddition(sym: Symbol) = sym == String_+ || sym == StringAdd_+ lazy val StringContext_f = getMemberMethod(StringContextClass, nme.f) diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index e06decea6d..a146f9aea5 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -169,17 +169,23 @@ class Flags extends ModifierFlags { final val SYNCHRONIZED = 1L << 45 // symbol is a method which should be marked ACC_SYNCHRONIZED + final val SYNTHESIZE_IMPL_IN_SUBCLASS = 1L << 50 // used in fields phase to indicate this accessor should receive an implementation in a subclass + + // flags used strictly internally in the Fields phase (info/tree transform): + final val NEEDS_TREES = 1L << 59 // this symbol needs a tree. (distinct from SYNTHESIZE_IMPL_IN_SUBCLASS) + // ------- shift definitions ------------------------------------------------------- // // Flags from 1L to (1L << 50) are normal flags. // - // The flags DEFERRED (1L << 4) to MODULE (1L << 8) have a `late` counterpart. Late flags change - // their counterpart from 0 to 1 after a specific phase (see below). The first late flag - // (lateDEFERRED) is at (1L << 51), i.e., late flags are shifted by 47. The last one is (1L << 55). + // The "late" counterpart to flags DEFERRED (1L << 4) to MODULE (1L << 8) + // show up in `sym.flags` as their regular counterpart once the phase mask admits them (see below). + // The first late flag (lateDEFERRED) is at (1L << 51), i.e., late flags are shifted by 47. The last one is (1L << 55). + // Think of it as a poor man's flag history akin to the type history for a symbol's info. // - // The flags PROTECTED (1L) to PRIVATE (1L << 2) have a `not` counterpart. Negated flags change - // their counterpart from 1 to 0 after a specific phase (see below). They are shifted by 56, i.e., - // the first negated flag (notPROTECTED) is at (1L << 56), the last at (1L << 58). + // The "not" counterpart to flags PROTECTED (1L) to PRIVATE (1L << 2) + // are negated flags that suppress their counterpart after a specific phase (see below). + // They are shifted by 56, i.e., the first negated flag (notPROTECTED) is at (1L << 56), the last at (1L << 58). // // Late and negative flags are only enabled after certain phases, implemented by the phaseNewFlags // method of the SubComponent, so they implement a bit of a flag history. @@ -211,20 +217,15 @@ class Flags extends ModifierFlags { // erasure 15 [START] <latedeferred> // mixin 20 [START] <latemodule> <notoverride> // - // lateMETHOD set in RefChecks#transformInfo. - // lateFINAL set in Symbols#makeNotPrivate. // notPRIVATE set in Symbols#makeNotPrivate, IExplicitOuter#transform, Inliners. // notPROTECTED set in ExplicitOuter#transform. - // lateDEFERRED set in AddInterfaces, Mixin, etc. - // lateMODULE set in Mixin#transformInfo. - // notOVERRIDE set in Mixin#preTransform. - final val lateDEFERRED = (DEFERRED: Long) << LateShift - final val lateFINAL = (FINAL: Long) << LateShift - final val lateMETHOD = (METHOD: Long) << LateShift - final val lateMODULE = (MODULE: Long) << LateShift +// final val lateDEFERRED = (DEFERRED: Long) << LateShift // unused +// final val lateFINAL = (FINAL: Long) << LateShift // only used for inliner -- could be subsumed by notPRIVATE? +// final val lateMETHOD = (METHOD: Long) << LateShift // unused +// final val lateMODULE = (MODULE: Long) << LateShift // unused - final val notOVERRIDE = (OVERRIDE: Long) << AntiShift +// final val notOVERRIDE = (OVERRIDE: Long) << AntiShift // unused final val notPRIVATE = (PRIVATE: Long) << AntiShift final val notPROTECTED = (PROTECTED: Long) << AntiShift @@ -257,7 +258,8 @@ class Flags extends ModifierFlags { /** These modifiers appear in TreePrinter output. */ final val PrintableFlags = ExplicitFlags | BridgeFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | MACRO | - ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED | ARTIFACT + ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED | ARTIFACT | + SYNTHESIZE_IMPL_IN_SUBCLASS | NEEDS_TREES /** When a symbol for a field is created, only these flags survive * from Modifiers. Others which may be applied at creation time are: @@ -442,16 +444,16 @@ class Flags extends ModifierFlags { case JAVA_DEFAULTMETHOD => "<defaultmethod>" // (1L << 47) case JAVA_ENUM => "<enum>" // (1L << 48) case JAVA_ANNOTATION => "<annotation>" // (1L << 49) - case 0x4000000000000L => "" // (1L << 50) - case `lateDEFERRED` => "<latedeferred>" // (1L << 51) - case `lateFINAL` => "<latefinal>" // (1L << 52) - case `lateMETHOD` => "<latemethod>" // (1L << 53) - case 0x80000000000000L => "" // (1L << 54) - case `lateMODULE` => "<latemodule>" // (1L << 55) + case SYNTHESIZE_IMPL_IN_SUBCLASS => "<sub_synth>" // (1L << 50) + case 0x08000000000000L => "<latedeferred>" // (1L << 51) + case 0x10000000000000L => "<latefinal>" // (1L << 52) + case 0x20000000000000L => "<latemethod>" // (1L << 53) + case 0x40000000000000L => "" // (1L << 54) + case 0x80000000000000L => "<latemodule>" // (1L << 55) case `notPROTECTED` => "<notprotected>" // (1L << 56) - case `notOVERRIDE` => "<notoverride>" // (1L << 57) + case 0x200000000000000L => "<notoverride>" // (1L << 57) case `notPRIVATE` => "<notprivate>" // (1L << 58) - case 0x800000000000000L => "" // (1L << 59) + case NEEDS_TREES => "<needs_trees>" // (1L << 59) case 0x1000000000000000L => "" // (1L << 60) case 0x2000000000000000L => "" // (1L << 61) case 0x4000000000000000L => "" // (1L << 62) diff --git a/src/reflect/scala/reflect/internal/Phase.scala b/src/reflect/scala/reflect/internal/Phase.scala index a761f686e6..eb193adbf2 100644 --- a/src/reflect/scala/reflect/internal/Phase.scala +++ b/src/reflect/scala/reflect/internal/Phase.scala @@ -47,6 +47,10 @@ abstract class Phase(val prev: Phase) { final val specialized: Boolean = ((prev ne null) && (prev ne NoPhase)) && (prev.name == "specialize" || prev.specialized) final val refChecked: Boolean = ((prev ne null) && (prev ne NoPhase)) && (prev.name == "refchecks" || prev.refChecked) + // are we past the fields phase, so that: + // - we should allow writing to vals (as part of type checking trait setters) + // - modules have module accessors + final val assignsFields: Boolean = ((prev ne null) && (prev ne NoPhase)) && (prev.name == "fields" || prev.assignsFields) /** This is used only in unsafeTypeParams, and at this writing is * overridden to false in parser, namer, typer, and erasure. (And NoPhase.) diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala index 30f2efd7e3..33ca78b439 100644 --- a/src/reflect/scala/reflect/internal/ReificationSupport.scala +++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala @@ -285,6 +285,7 @@ trait ReificationSupport { self: SymbolTable => val (gvdefs, etdefs) = rawEdefs.partition(treeInfo.isEarlyValDef) val (fieldDefs, UnCtor(ctorMods, ctorVparamss, lvdefs) :: body) = rest.splitAt(indexOfCtor(rest)) val evdefs = gvdefs.zip(lvdefs).map { + // TODO: in traits, early val defs are defdefs case (gvdef @ ValDef(_, _, tpt: TypeTree, _), ValDef(_, _, _, rhs)) => copyValDef(gvdef)(tpt = tpt.original, rhs = rhs) case (tr1, tr2) => diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 11b5db9793..925018d3a6 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -95,6 +95,8 @@ trait StdNames { val NAME_JOIN_STRING: String = NameTransformer.NAME_JOIN_STRING val MODULE_SUFFIX_STRING: String = NameTransformer.MODULE_SUFFIX_STRING val LOCAL_SUFFIX_STRING: String = NameTransformer.LOCAL_SUFFIX_STRING + val LAZY_LOCAL_SUFFIX_STRING: String = NameTransformer.LAZY_LOCAL_SUFFIX_STRING + val TRAIT_SETTER_SEPARATOR_STRING: String = NameTransformer.TRAIT_SETTER_SEPARATOR_STRING val SINGLETON_SUFFIX: String = ".type" @@ -337,7 +339,6 @@ trait StdNames { val DEFAULT_CASE: NameType = "defaultCase$" val EQEQ_LOCAL_VAR: NameType = "eqEqTemp$" val FAKE_LOCAL_THIS: NameType = "this$" - val LAZY_LOCAL: NameType = "$lzy" val LAZY_SLOW_SUFFIX: NameType = "$lzycompute" val UNIVERSE_BUILD_PREFIX: NameType = "$u.internal.reificationSupport." val UNIVERSE_PREFIX: NameType = "$u." diff --git a/src/reflect/scala/reflect/internal/SymbolPairs.scala b/src/reflect/scala/reflect/internal/SymbolPairs.scala index a52d2d8510..320c814696 100644 --- a/src/reflect/scala/reflect/internal/SymbolPairs.scala +++ b/src/reflect/scala/reflect/internal/SymbolPairs.scala @@ -30,27 +30,6 @@ abstract class SymbolPairs { val global: SymbolTable import global._ - /** Type operations relative to a prefix. All operations work on Symbols, - * and the types are the member types of those symbols in the prefix. - */ - class RelativeTo(val prefix: Type) { - def this(clazz: Symbol) = this(clazz.thisType) - import scala.language.implicitConversions // geez, it even has to hassle me when it's private - private implicit def symbolToType(sym: Symbol): Type = prefix memberType sym - - def erasureOf(sym: Symbol): Type = erasure.erasure(sym)(sym: Type) - def signature(sym: Symbol): String = sym defStringSeenAs (sym: Type) - def erasedSignature(sym: Symbol): String = sym defStringSeenAs erasureOf(sym) - - def isSameType(sym1: Symbol, sym2: Symbol): Boolean = sym1 =:= sym2 - def isSubType(sym1: Symbol, sym2: Symbol): Boolean = sym1 <:< sym2 - def isSuperType(sym1: Symbol, sym2: Symbol): Boolean = sym2 <:< sym1 - def isSameErasure(sym1: Symbol, sym2: Symbol): Boolean = erasureOf(sym1) =:= erasureOf(sym2) - def matches(sym1: Symbol, sym2: Symbol): Boolean = (sym1: Type) matches (sym2: Type) - - override def toString = s"RelativeTo($prefix)" - } - /** Are types tp1 and tp2 equivalent seen from the perspective * of `baseClass`? For instance List[Int] and Seq[Int] are =:= * when viewed from IterableClass. @@ -58,10 +37,11 @@ abstract class SymbolPairs { def sameInBaseClass(baseClass: Symbol)(tp1: Type, tp2: Type) = (tp1 baseType baseClass) =:= (tp2 baseType baseClass) - case class SymbolPair(base: Symbol, low: Symbol, high: Symbol) { + final case class SymbolPair(base: Symbol, low: Symbol, high: Symbol) { + private[this] val self = base.thisType + def pos = if (low.owner == base) low.pos else if (high.owner == base) high.pos else base.pos - def self: Type = base.thisType - def rootType: Type = base.thisType + def rootType: Type = self def lowType: Type = self memberType low def lowErased: Type = erasure.specialErasure(base)(low.tpe) diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index ab52a875f8..487aadf5e5 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -96,8 +96,12 @@ trait Symbols extends api.Symbols { self: SymbolTable => def isByNameParam: Boolean = this.isValueParameter && (this hasFlag BYNAMEPARAM) def isImplementationArtifact: Boolean = (this hasFlag BRIDGE) || (this hasFlag VBRIDGE) || (this hasFlag ARTIFACT) def isJava: Boolean = isJavaDefined - def isVal: Boolean = isTerm && !isModule && !isMethod && !isMutable - def isVar: Boolean = isTerm && !isModule && !isMethod && !isLazy && isMutable + + def isField: Boolean = isTerm && !isModule && (!isMethod || owner.isTrait && isAccessor) + def isMutableVal = if (owner.isTrait) !hasFlag(STABLE) else isMutable + def isVal: Boolean = isField && !isMutableVal + def isVar: Boolean = isField && !isLazy && isMutableVal + def isAbstract: Boolean = isAbstractClass || isDeferred || isAbstractType def isPrivateThis = (this hasFlag PRIVATE) && (this hasFlag LOCAL) def isProtectedThis = (this hasFlag PROTECTED) && (this hasFlag LOCAL) @@ -320,17 +324,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def newImport(pos: Position): TermSymbol = newTermSymbol(nme.IMPORT, pos) - def newModuleVarSymbol(accessor: Symbol): TermSymbol = { - val newName = nme.moduleVarName(accessor.name.toTermName) - val newFlags = MODULEVAR | ( if (this.isClass) PrivateLocal | SYNTHETIC else 0 ) - val newInfo = thisType.memberType(accessor).finalResultType - val mval = newVariable(newName, accessor.pos.focus, newFlags.toLong) addAnnotation VolatileAttr - - if (this.isClass) - mval setInfoAndEnter newInfo - else - mval setInfo newInfo - } final def newModuleSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol = newTermSymbol(name, pos, newFlags).asInstanceOf[ModuleSymbol] @@ -753,10 +746,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def hasGetter = isTerm && nme.isLocalName(name) /** - * Nested modules which have no static owner when ModuleDefs are eliminated (refchecks) are - * given the lateMETHOD flag, which makes them appear as methods after refchecks. + * Nested modules with a non-static owner receive the METHOD flag during UnCurry's info transform. + * (They are replaced by a ClassDef and DefDef for the module accessor during the fields phase.) * - * Note: the lateMETHOD flag is added lazily in the info transformer of the RefChecks phase. + * Note: the METHOD flag is added lazily in the info transformer of the UnCurry phase. * This means that forcing the `sym.info` may change the value of `sym.isMethod`. Forcing the * info is in the responsibility of the caller. Doing it eagerly here was tried (0ccdb151f) but * has proven to lead to bugs (SI-8907). @@ -992,10 +985,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isEffectivelyFinal: Boolean = ( (this hasFlag FINAL | PACKAGE) || isModuleOrModuleClass && (isTopLevel || !settings.overrideObjects) - || isTerm && ( - isPrivate - || isLocalToBlock - ) + || isTerm && (isPrivate || isLocalToBlock || (hasAllFlags(notPRIVATE | METHOD) && !hasFlag(DEFERRED))) || isClass && originalOwner.isTerm && children.isEmpty // we track known subclasses of term-owned classes, use that infer finality ) /** Is this symbol effectively final or a concrete term member of sealed class whose children do not override it */ @@ -1532,7 +1522,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => def setInfo(info: Type): this.type = { info_=(info); this } /** Modifies this symbol's info in place. */ def modifyInfo(f: Type => Type): this.type = setInfo(f(info)) - /** Substitute second list of symbols for first in current info. */ + /** Substitute second list of symbols for first in current info. + * + * NOTE: this discards the type history (uses setInfo) + */ def substInfo(syms0: List[Symbol], syms1: List[Symbol]): this.type = if (syms0.isEmpty) this else modifyInfo(_.substSym(syms0, syms1)) @@ -2048,7 +2041,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => assert(hasAccessorFlag, this) val localField = owner.info decl localName - if (localField == NoSymbol && this.hasFlag(MIXEDIN)) { + if (localField == NoSymbol && this.hasFlag(MIXEDIN)) { // TODO: fields phase does not (yet?) add MIXEDIN in setMixedinAccessorFlags // SI-8087: private[this] fields don't have a `localName`. When searching the accessed field // for a mixin accessor of such a field, we need to look for `name` instead. // The phase travel ensures that the field is found (`owner` is the trait class symbol, the @@ -2088,8 +2081,15 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** If this is a lazy value, the lazy accessor; otherwise this symbol. */ def lazyAccessorOrSelf: Symbol = if (isLazy) lazyAccessor else this - /** If this is an accessor, the accessed symbol. Otherwise, this symbol. */ - def accessedOrSelf: Symbol = if (hasAccessorFlag) accessed else this + /** `accessed`, if this is an accessor that should have an underlying field. Otherwise, `this`. + * Note that a "regular" accessor in a trait does not have a field, as an interface cannot define a field. + * "non-regular" vals are: early initialized or lazy vals. + * Eventually, we should delay introducing symbols for all val/vars until the fields (or lazyvals) phase, + * as they are an implementation detail that's irrelevant to type checking. + */ + def accessedOrSelf: Symbol = + if (hasAccessorFlag && (!owner.isTrait || hasFlag(PRESUPER | LAZY))) accessed + else this /** For an outer accessor: The class from which the outer originates. * For all other symbols: NoSymbol @@ -2447,14 +2447,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ final def makeNotPrivate(base: Symbol) { if (this.isPrivate) { - setFlag(notPRIVATE) - // Marking these methods final causes problems for proxies which use subclassing. If people - // write their code with no usage of final, we probably shouldn't introduce it ourselves - // unless we know it is safe. ... Unfortunately if they aren't marked final the inliner - // thinks it can't inline them. So once again marking lateFINAL, and in genjvm we no longer - // generate ACC_FINAL on "final" methods which are actually lateFINAL. - if (isMethod && !isDeferred) - setFlag(lateFINAL) + setFlag(notPRIVATE) // this makes it effectively final (isEffectivelyFinal) + // don't set FINAL -- methods not marked final by user should not end up final in bytecode + // inliner will know it's effectively final (notPRIVATE non-deferred method) if (!isStaticModule && !isClassConstructor) { expandName(base) if (isModule) moduleClass.makeNotPrivate(base) @@ -2532,30 +2527,34 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def symbolKind: SymbolKind = { var kind = - if (isTermMacro) ("term macro", "macro method", "MACM") - else if (isInstanceOf[FreeTermSymbol]) ("free term", "free term", "FTE") - else if (isInstanceOf[FreeTypeSymbol]) ("free type", "free type", "FTY") - else if (isPackageClass) ("package class", "package", "PKC") - else if (hasPackageFlag) ("package", "package", "PK") - else if (isPackageObject) ("package object", "package", "PKO") - else if (isPackageObjectClass) ("package object class", "package", "PKOC") - else if (isAnonymousClass) ("anonymous class", "anonymous class", "AC") - else if (isRefinementClass) ("refinement class", "", "RC") - else if (isModule) ("module", "object", "MOD") - else if (isModuleClass) ("module class", "object", "MODC") - else if (isGetter) ("getter", if (isSourceMethod) "method" else "value", "GET") - else if (isSetter) ("setter", if (isSourceMethod) "method" else "value", "SET") - else if (isTerm && isLazy) ("lazy value", "lazy value", "LAZ") - else if (isVariable) ("field", "variable", "VAR") - else if (isTrait) ("trait", "trait", "TRT") - else if (isClass) ("class", "class", "CLS") - else if (isType) ("type", "type", "TPE") - else if (isClassConstructor && (owner.hasCompleteInfo && isPrimaryConstructor)) ("primary constructor", "constructor", "PCTOR") - else if (isClassConstructor) ("constructor", "constructor", "CTOR") - else if (isSourceMethod) ("method", "method", "METH") - else if (isTerm) ("value", "value", "VAL") - else ("", "", "???") + if (isTermMacro) ("term macro", "macro method", "MACM") + else if (isInstanceOf[FreeTermSymbol]) ("free term", "free term", "FTE") + else if (isInstanceOf[FreeTypeSymbol]) ("free type", "free type", "FTY") + else if (isPackageClass) ("package class", "package", "PKC") + else if (hasPackageFlag) ("package", "package", "PK") + else if (isPackageObject) ("package object", "package", "PKO") + else if (isPackageObjectClass) ("package object class", "package", "PKOC") + else if (isAnonymousClass) ("anonymous class", "anonymous class", "AC") + else if (isRefinementClass) ("refinement class", "", "RC") + else if (isModule) ("module", "object", "MOD") + else if (isModuleClass) ("module class", "object", "MODC") + else if (isAccessor && + !hasFlag(STABLE | LAZY)) ("setter", "variable", "SET") + else if (isAccessor && !hasFlag(LAZY)) ("getter", "value", "GET") + else if (isTerm && hasFlag(LAZY)) ("lazy value", "lazy value", "LAZ") + else if (isVariable) ("field", "variable", "VAR") + else if (isTrait) ("trait", "trait", "TRT") + else if (isClass) ("class", "class", "CLS") + else if (isType) ("type", "type", "TPE") + else if (isClassConstructor && (owner.hasCompleteInfo && + isPrimaryConstructor)) ("primary constructor", "constructor", "PCTOR") + else if (isClassConstructor) ("constructor", "constructor", "CTOR") + else if (isMethod) ("method", "method", "METH") + else if (isTerm) ("value", "value", "VAL") + else ("", "", "???") + if (isSkolem) kind = (kind._1, kind._2, kind._3 + "#SKO") + SymbolKind(kind._1, kind._2, kind._3) } @@ -2623,12 +2622,17 @@ trait Symbols extends api.Symbols { self: SymbolTable => * If hasMeaninglessName is true, uses the owner's name to disambiguate identity. */ override def toString: String = { - if (isPackageObjectOrClass && !settings.debug) - s"package object ${owner.decodedName}" - else compose( - kindString, - if (hasMeaninglessName) owner.decodedName + idString else nameString - ) + val simplifyNames = !settings.debug + if (isPackageObjectOrClass && simplifyNames) s"package object ${owner.decodedName}" + else { + val kind = kindString + val _name: String = + if (hasMeaninglessName) owner.decodedName + idString + else if (simplifyNames && (kind == "variable" || kind == "value")) unexpandedName.getterName.decode.toString // TODO: make condition less gross? + else nameString + + compose(kind, _name) + } } /** String representation of location. @@ -2764,18 +2768,21 @@ trait Symbols extends api.Symbols { self: SymbolTable => ) ***/ override def isValueParameter = this hasFlag PARAM - override def isSetterParameter = isValueParameter && owner.isSetter - override def isAccessor = this hasFlag ACCESSOR - override def isGetter = isAccessor && !isSetter + override def isDefaultGetter = name containsName nme.DEFAULT_GETTER_STRING - override def isSetter = isAccessor && nme.isSetterName(name) // todo: make independent of name, as this can be forged. + + override def isAccessor = this hasFlag ACCESSOR + override def isGetter = isAccessor && !nme.isSetterName(name) // TODO: make independent of name, as this can be forged. + override def isSetter = isAccessor && nme.isSetterName(name) // TODO: make independent of name, as this can be forged. + override def isLocalDummy = nme.isLocalDummyName(name) + override def isClassConstructor = name == nme.CONSTRUCTOR override def isMixinConstructor = name == nme.MIXIN_CONSTRUCTOR - override def isConstructor = nme.isConstructorName(name) + override def isConstructor = isClassConstructor || isMixinConstructor - override def isPackageObject = isModule && (name == nme.PACKAGE) + override def isPackageObject = isModule && (name == nme.PACKAGE) // The name in comments is what it is being disambiguated from. // TODO - rescue CAPTURED from BYNAMEPARAM so we can see all the names. @@ -2871,7 +2878,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def owner = { if (Statistics.hotEnabled) Statistics.incCounter(ownerCount) - // a module symbol may have the lateMETHOD flag after refchecks, see isModuleNotMethod + // a non-static module symbol gets the METHOD flag in uncurry's info transform -- see isModuleNotMethod if (!isMethod && needsFlatClasses) rawowner.owner else rawowner } @@ -2891,38 +2898,23 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** A class for method symbols */ class MethodSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TermName) extends TermSymbol(initOwner, initPos, initName) with MethodSymbolApi { - private[this] var mtpePeriod = NoPeriod - private[this] var mtpePre: Type = _ - private[this] var mtpeResult: Type = _ - private[this] var mtpeInfo: Type = _ - override def isLabel = this hasFlag LABEL override def isVarargsMethod = this hasFlag VARARGS override def isLiftedMethod = this hasFlag LIFTED - // TODO - this seems a strange definition for "isSourceMethod", given that - // it does not make any specific effort to exclude synthetics. Figure out what - // this method is really for and what logic makes sense. - override def isSourceMethod = !(this hasFlag STABLE) // exclude all accessors + // TODO: this definition of isSourceMethod makes no sense -- inline it and re-evaluate at each call site. + // I'm guessing it meant "method written by user, and not generated by the compiler" + // (And then assuming those generated by the compiler don't require certain transformations?) + // Use SYNTHETIC/ARTIFACT instead as an indicator? I don't see how it makes sense to only exclude getters. + // Note also that trait vals are modelled as getters, and thus that user-supplied code appears in their rhs. + // Originally, it may have been an optimization to skip methods that were not user-defined (getters), + // but it doesn't even exclude setters, contrary to its original comment (// exclude all accessors) + override def isSourceMethod = !(this hasFlag STABLE) + // unfortunately having the CASEACCESSOR flag does not actually mean you // are a case accessor (you can also be a field.) override def isCaseAccessorMethod = isCaseAccessor - def typeAsMemberOf(pre: Type): Type = { - if (mtpePeriod == currentPeriod) { - if ((mtpePre eq pre) && (mtpeInfo eq info)) return mtpeResult - } else if (isValid(mtpePeriod)) { - mtpePeriod = currentPeriod - if ((mtpePre eq pre) && (mtpeInfo eq info)) return mtpeResult - } - val res = pre.computeMemberType(this) - mtpePeriod = currentPeriod - mtpePre = pre - mtpeInfo = info - mtpeResult = res - res - } - override def isVarargs: Boolean = definitions.isVarArgsList(paramss.flatten) override def returnType: Type = { @@ -3231,7 +3223,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * returned, otherwise, `NoSymbol` is returned. */ protected final def companionModule0: Symbol = - flatOwnerInfo.decl(name.toTermName).suchThat(sym => sym.isModuleNotMethod && (sym isCoDefinedWith this)) + flatOwnerInfo.decl(name.toTermName).suchThat(sym => sym.isModule && (sym isCoDefinedWith this)) override def companionModule = companionModule0 override def companionSymbol = companionModule0 diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 895bb60a08..7dda805378 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -686,23 +686,21 @@ trait Types * }}} */ def memberInfo(sym: Symbol): Type = { - require(sym ne NoSymbol, this) +// assert(sym ne NoSymbol, this) sym.info.asSeenFrom(this, sym.owner) } /** The type of `sym`, seen as a member of this type. */ - def memberType(sym: Symbol): Type = sym match { - case meth: MethodSymbol => - meth.typeAsMemberOf(this) - case _ => - computeMemberType(sym) - } - - def computeMemberType(sym: Symbol): Type = sym.tpeHK match { //@M don't prematurely instantiate higher-kinded types, they will be instantiated by transform, typedTypeApply, etc. when really necessary - case OverloadedType(_, alts) => - OverloadedType(this, alts) + def memberType(sym: Symbol): Type = sym.tpeHK match { + case OverloadedType(_, alts) => OverloadedType(this, alts) case tp => - if (sym eq NoSymbol) NoType else tp.asSeenFrom(this, sym.owner) + // Correct caching is nearly impossible because `sym.tpeHK.asSeenFrom(pre, sym.owner)` + // may have different results even for reference-identical `sym.tpeHK` and `pre` (even in the same period). + // For example, `pre` could be a `ThisType`. For such a type, `tpThen eq tpNow` does not imply + // `tpThen` and `tpNow` mean the same thing, because `tpThen.typeSymbol.info` could have been different + // from what it is now, and the cache won't know simply by looking at `pre`. + if (sym eq NoSymbol) NoType + else tp.asSeenFrom(this, sym.owner) } /** Substitute types `to` for occurrences of references to @@ -3471,10 +3469,10 @@ trait Types if (!sym.isOverridableMember || sym.owner == pre.typeSymbol) sym else pre.nonPrivateMember(sym.name).suchThat { sym => // SI-7928 `isModuleNotMethod` is here to avoid crashing with spuriously "overloaded" module accessor and module symbols. - // These appear after refchecks eliminates ModuleDefs that implement an interface. + // These appear after the fields phase eliminates ModuleDefs that implement an interface. // Here, we exclude the module symbol, which allows us to bind to the accessor. - // SI-8054 We must only do this after refchecks, otherwise we exclude the module symbol which does not yet have an accessor! - val isModuleWithAccessor = phase.refChecked && sym.isModuleNotMethod + // SI-8054 We must only do this after fields, otherwise we exclude the module symbol which does not yet have an accessor! + val isModuleWithAccessor = phase.assignsFields && sym.isModuleNotMethod sym.isType || (!isModuleWithAccessor && sym.isStable && !sym.hasVolatileType) } orElse sym } diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala index 69bade55f1..bc8a5de119 100644 --- a/src/reflect/scala/reflect/internal/Variances.scala +++ b/src/reflect/scala/reflect/internal/Variances.scala @@ -167,7 +167,9 @@ trait Variances { case ClassDef(_, _, _, _) | TypeDef(_, _, _, _) => validateVariance(sym) super.traverse(tree) - // ModuleDefs need not be considered because they have been eliminated already + case ModuleDef(_, _, _) => + validateVariance(sym.moduleClass) + super.traverse(tree) case ValDef(_, _, _, _) => validateVariance(sym) case DefDef(_, _, tparams, vparamss, _, _) => diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index 412c49f571..62ca50d035 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -148,9 +148,19 @@ trait Erasure { apply(atp) case ClassInfoType(parents, decls, clazz) => ClassInfoType( - if (clazz == ObjectClass || isPrimitiveValueClass(clazz)) Nil + if (clazz == ObjectClass || isPrimitiveValueClass(clazz) || parents.isEmpty) Nil else if (clazz == ArrayClass) ObjectTpe :: Nil - else removeLaterObjects(parents map this), + else { + val erasedParents = parents map this + + // drop first parent for traits -- it has been normalized to a class by now, + // but we should drop that in bytecode + val firstParent = + if (clazz.hasFlag(Flags.TRAIT) && !clazz.hasFlag(Flags.JAVA)) ObjectTpe + else erasedParents.head + + firstParent :: erasedParents.tail.filter(_.typeSymbol != ObjectClass) + }, decls, clazz) case _ => mapOver(tp) diff --git a/src/reflect/scala/reflect/internal/transform/RefChecks.scala b/src/reflect/scala/reflect/internal/transform/RefChecks.scala index 4ca114e781..e69de29bb2 100644 --- a/src/reflect/scala/reflect/internal/transform/RefChecks.scala +++ b/src/reflect/scala/reflect/internal/transform/RefChecks.scala @@ -1,14 +0,0 @@ -package scala -package reflect -package internal -package transform - -trait RefChecks { - - val global: SymbolTable - import global._ - - def transformInfo(sym: Symbol, tp: Type): Type = - if (sym.isModule && !sym.isStatic) NullaryMethodType(tp) - else tp -} diff --git a/src/reflect/scala/reflect/internal/transform/Transforms.scala b/src/reflect/scala/reflect/internal/transform/Transforms.scala index 0d2f355aa5..de5bfbd39a 100644 --- a/src/reflect/scala/reflect/internal/transform/Transforms.scala +++ b/src/reflect/scala/reflect/internal/transform/Transforms.scala @@ -23,12 +23,10 @@ trait Transforms { self: SymbolTable => } } - private val refChecksLazy = new Lazy(new { val global: Transforms.this.type = self } with RefChecks) private val uncurryLazy = new Lazy(new { val global: Transforms.this.type = self } with UnCurry) private val erasureLazy = new Lazy(new { val global: Transforms.this.type = self } with Erasure) private val postErasureLazy = new Lazy(new { val global: Transforms.this.type = self } with PostErasure) - def refChecks = refChecksLazy.force def uncurry = uncurryLazy.force def erasure = erasureLazy.force def postErasure = postErasureLazy.force @@ -36,8 +34,7 @@ trait Transforms { self: SymbolTable => def transformedType(sym: Symbol) = postErasure.transformInfo(sym, erasure.transformInfo(sym, - uncurry.transformInfo(sym, - refChecks.transformInfo(sym, sym.info)))) + uncurry.transformInfo(sym, sym.info))) def transformedType(tpe: Type) = postErasure.elimErasedValueType(erasure.scalaErasure(uncurry.uncurry(tpe))) diff --git a/src/reflect/scala/reflect/internal/transform/UnCurry.scala b/src/reflect/scala/reflect/internal/transform/UnCurry.scala index 85e3ac60e8..a50084f40d 100644 --- a/src/reflect/scala/reflect/internal/transform/UnCurry.scala +++ b/src/reflect/scala/reflect/internal/transform/UnCurry.scala @@ -83,5 +83,10 @@ trait UnCurry { * @MAT: starting with this phase, the info of every symbol will be normalized */ def transformInfo(sym: Symbol, tp: Type): Type = - if (sym.isType) uncurryType(tp) else uncurry(tp) + if (sym.isType) uncurryType(tp) + else if ((sym hasFlag MODULE) && !sym.isStatic) { // see Fields::nonStaticModuleToMethod + sym setFlag METHOD | STABLE + MethodType(Nil, uncurry(tp)) + } + else uncurry(tp) } diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index 0a90a141d3..caef5535b4 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -247,7 +247,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.SymbolModule definitions.StringAddClass definitions.ScalaNumberClass - definitions.TraitSetterAnnotationClass definitions.DelayedInitClass definitions.TypeConstraintClass definitions.SingletonClass diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index 313ec89311..237afa082b 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -199,12 +199,7 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb trait SynchronizedTermSymbol extends SynchronizedSymbol - trait SynchronizedMethodSymbol extends MethodSymbol with SynchronizedTermSymbol { - // we can keep this lock fine-grained, because it's just a cache over asSeenFrom, which makes deadlocks impossible - // unfortunately we cannot elide this lock, because the cache depends on `pre` - private lazy val typeAsMemberOfLock = new Object - override def typeAsMemberOf(pre: Type): Type = gilSynchronizedIfNotThreadsafe { typeAsMemberOfLock.synchronized { super.typeAsMemberOf(pre) } } - } + trait SynchronizedMethodSymbol extends MethodSymbol with SynchronizedTermSymbol trait SynchronizedModuleSymbol extends ModuleSymbol with SynchronizedTermSymbol |