diff options
author | Adriaan Moors <adriaan@lightbend.com> | 2016-09-01 10:41:28 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-09-01 10:41:28 +0200 |
commit | f90bf565a529d0e95155992a3c243952183f25a5 (patch) | |
tree | 151f8d8d79dba64a96d12b1c4a9c4fa38269dcf8 /src/reflect | |
parent | 45edf8699f76faa5d1b035fb8f887621bcbb9934 (diff) | |
parent | 743f0d2c2a33bc8ab0c1f7bee796865672ba2fcc (diff) | |
download | scala-f90bf565a529d0e95155992a3c243952183f25a5.tar.gz scala-f90bf565a529d0e95155992a3c243952183f25a5.tar.bz2 scala-f90bf565a529d0e95155992a3c243952183f25a5.zip |
Merge pull request #5294 from adriaanm/fields-lazies
Fields: expand lazy vals during fields, like modules
Diffstat (limited to 'src/reflect')
7 files changed, 64 insertions, 43 deletions
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index d0539dfd42..89d1b0637a 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -81,7 +81,7 @@ trait Definitions extends api.StandardDefinitions { } } - private[Definitions] def classesMap[T](f: Name => T) = symbolsMap(ScalaValueClassesNoUnit, f) + private[Definitions] def classesMap[T](f: Name => T): Map[Symbol, T] = symbolsMap(ScalaValueClassesNoUnit, f) private def symbolsMap[T](syms: List[Symbol], f: Name => T): Map[Symbol, T] = mapFrom(syms)(x => f(x.name)) private def symbolsMapFilt[T](syms: List[Symbol], p: Name => Boolean, f: Name => T) = symbolsMap(syms filter (x => p(x.name)), f) @@ -93,6 +93,9 @@ trait Definitions extends api.StandardDefinitions { lazy val boxedClass = classesMap(x => getClassByName(boxedName(x))) lazy val refClass = classesMap(x => getRequiredClass("scala.runtime." + x + "Ref")) lazy val volatileRefClass = classesMap(x => getRequiredClass("scala.runtime.Volatile" + x + "Ref")) + lazy val lazyHolders = symbolsMap(ScalaValueClasses, x => getClassIfDefined("scala.runtime.Lazy" + x)) + lazy val LazyRefClass = getClassIfDefined("scala.runtime.LazyRef") + lazy val LazyUnitClass = getClassIfDefined("scala.runtime.LazyUnit") lazy val allRefClasses: Set[Symbol] = { refClass.values.toSet ++ volatileRefClass.values.toSet ++ Set(VolatileObjectRefClass, ObjectRefClass) diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 925018d3a6..c8e4d3d1d5 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -704,6 +704,7 @@ trait StdNames { val immutable: NameType = "immutable" val implicitly: NameType = "implicitly" val in: NameType = "in" + val initialized : NameType = "initialized" val internal: NameType = "internal" val inlinedEquals: NameType = "inlinedEquals" val isArray: NameType = "isArray" diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 487aadf5e5..ac025e50ae 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -655,7 +655,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => isClass && isFinal && loop(typeParams) } - final def isLazyAccessor = isLazy && lazyAccessor != NoSymbol final def isOverridableMember = !(isClass || isEffectivelyFinal) && safeOwner.isClass /** Does this symbol denote a wrapper created by the repl? */ @@ -1683,7 +1682,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * * - packageobjects (follows namer) * - superaccessors (follows typer) - * - lazyvals (follows erasure) + * - lambdaLift (follows erasure) * - null */ private def unsafeTypeParamPhase = { @@ -2075,11 +2074,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ def alias: Symbol = NoSymbol - /** For a lazy value, its lazy accessor. NoSymbol for all others. */ + @deprecated("No longer applicable, as lazy vals are not desugared until the fields phase", "2.12.0") // used by scala-refactoring def lazyAccessor: Symbol = NoSymbol - /** If this is a lazy value, the lazy accessor; otherwise this symbol. */ - def lazyAccessorOrSelf: Symbol = if (isLazy) lazyAccessor else this + @deprecated("No longer applicable, as lazy vals are not desugared until the fields phase", "2.12.0") + def lazyAccessorOrSelf: Symbol = NoSymbol /** `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. @@ -2088,7 +2087,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * as they are an implementation detail that's irrelevant to type checking. */ def accessedOrSelf: Symbol = - if (hasAccessorFlag && (!owner.isTrait || hasFlag(PRESUPER | LAZY))) accessed + if (hasAccessorFlag && (!owner.isTrait || hasFlag(PRESUPER))) accessed else this /** For an outer accessor: The class from which the outer originates. @@ -2834,17 +2833,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => this } - def setLazyAccessor(sym: Symbol): TermSymbol = { - assert(isLazy && (referenced == NoSymbol || referenced == sym), (this, debugFlagString, referenced, sym)) - referenced = sym - this - } - - override def lazyAccessor: Symbol = { - assert(isLazy, this) - referenced - } - /** change name by appending $$<fully-qualified-name-of-class `base`> * Do the same for any accessed symbols or setters/getters */ diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index b9f3e987ee..61937958dd 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -293,6 +293,26 @@ abstract class TreeInfo { } } + + // No field for these vals, which means the ValDef carries the symbol of the getter (and not the field symbol) + // - abstract vals have no value we could store (until they become concrete, potentially) + // - lazy vals: the ValDef carries the symbol of the lazy accessor. + // The sausage factory will spew out the inner workings during the fields phase (actual bitmaps won't follow + // until lazyvals & mixins, though we should move this stuff from mixins to lazyvals now that fields takes care of mixing in lazy vals) + // - concrete vals in traits don't yield a field here either (their getter's RHS has the initial value) + // Constructors will move the assignment to the constructor, abstracting over the field using the field setter, + // and Fields will add a field to the class that mixes in the trait, implementing the accessors in terms of it + // + // The following case does receive a field symbol (until it's eliminated during the fields phase): + // - a concrete val with a statically known value (ConstantType) + // performs its side effect according to lazy/strict semantics, but doesn't need to store its value + // each access will "evaluate" the RHS (a literal) again + // + // We would like to avoid emitting unnecessary fields, but the required knowledge isn't available until after typer. + // The only way to avoid emitting & suppressing, is to not emit at all until we are sure to need the field, as dotty does. + def noFieldFor(vd: ValDef, owner: Symbol) = vd.mods.isDeferred || vd.mods.isLazy || (owner.isTrait && !vd.mods.hasFlag(PRESUPER)) + + def isDefaultGetter(tree: Tree) = { tree.symbol != null && tree.symbol.isDefaultGetter } diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index 4bc804445c..c6cb0d0223 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -227,9 +227,7 @@ abstract class UnPickler { return NoSymbol if (tag == EXTMODCLASSref) { - val moduleVar = owner.info.decl(nme.moduleVarName(name.toTermName)) - if (moduleVar.isLazyAccessor) - return moduleVar.lazyAccessor.lazyAccessor + owner.info.decl(nme.moduleVarName(name.toTermName)) } NoSymbol } diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index 62ca50d035..e2f1e74740 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -147,21 +147,20 @@ trait Erasure { case AnnotatedType(_, atp) => apply(atp) case ClassInfoType(parents, decls, clazz) => - ClassInfoType( - if (clazz == ObjectClass || isPrimitiveValueClass(clazz) || parents.isEmpty) Nil + val newParents = + if (parents.isEmpty || clazz == ObjectClass || isPrimitiveValueClass(clazz)) Nil else if (clazz == ArrayClass) ObjectTpe :: Nil else { - val erasedParents = parents map this + val erasedParents = parents mapConserve 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) + if (clazz.hasFlag(Flags.TRAIT) && !clazz.hasFlag(Flags.JAVA)) + ObjectTpe :: erasedParents.tail.filter(_.typeSymbol != ObjectClass) + else erasedParents + } + if (newParents eq parents) tp + else ClassInfoType(newParents, decls, clazz) case _ => mapOver(tp) } @@ -343,23 +342,30 @@ trait Erasure { } } - /** The symbol's erased info. This is the type's erasure, except for the following symbols: - * - * - For $asInstanceOf : [T]T - * - For $isInstanceOf : [T]scala#Boolean - * - For class Array : [T]C where C is the erased classinfo of the Array class. - * - For Array[T].<init> : {scala#Int)Array[T] - * - For a type parameter : A type bounds type consisting of the erasures of its bounds. - */ + /** The symbol's erased info. This is the type's erasure, except for the following primitive symbols: + * + * - $asInstanceOf --> [T]T + * - $isInstanceOf --> [T]scala#Boolean + * - synchronized --> [T](x: T)T + * - class Array --> [T]C where C is the erased classinfo of the Array class. + * - Array[T].<init> --> {scala#Int)Array[T] + * + * An abstract type's info erases to a TypeBounds type consisting of the erasures of the abstract type's bounds. + */ def transformInfo(sym: Symbol, tp: Type): Type = { - if (sym == Object_asInstanceOf) + // Do not erase the primitive `synchronized` method's info or the info of its parameter. + // We do erase the info of its type param so that subtyping can relate its bounds after erasure. + def synchronizedPrimitive(sym: Symbol) = + sym == Object_synchronized || (sym.owner == Object_synchronized && sym.isTerm) + + if (sym == Object_asInstanceOf || synchronizedPrimitive(sym)) sym.info else if (sym == Object_isInstanceOf || sym == ArrayClass) PolyType(sym.info.typeParams, specialErasure(sym)(sym.info.resultType)) else if (sym.isAbstractType) - TypeBounds(WildcardType, WildcardType) + TypeBounds(WildcardType, WildcardType) // TODO why not use the erasure of the type's bounds, as stated in the doc? else if (sym.isTerm && sym.owner == ArrayClass) { - if (sym.isClassConstructor) + if (sym.isClassConstructor) // TODO: switch on name for all branches -- this one is sym.name == nme.CONSTRUCTOR tp match { case MethodType(params, TypeRef(pre, sym1, args)) => MethodType(cloneSymbolsAndModify(params, specialErasure(sym)), @@ -376,12 +382,14 @@ trait Erasure { } else if ( sym.owner != NoSymbol && sym.owner.owner == ArrayClass && - sym == Array_update.paramss.head(1)) { + sym == Array_update.paramss.head(1)) { // TODO: can we simplify the guard, perhaps cache the symbol to compare to? // special case for Array.update: the non-erased type remains, i.e. (Int,A)Unit // since the erasure type map gets applied to every symbol, we have to catch the // symbol here tp } else { + // TODO OPT: altogether, there are 9 symbols that we special-case. + // Could we get to the common case more quickly by looking them up in a set? specialErasure(sym)(tp) } } diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index f55b33959a..d56cecc965 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -432,6 +432,9 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.boxedClass definitions.refClass definitions.volatileRefClass + definitions.lazyHolders + definitions.LazyRefClass + definitions.LazyUnitClass definitions.allRefClasses definitions.UnitClass definitions.ByteClass |