summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan@lightbend.com>2016-09-01 10:41:28 +0200
committerGitHub <noreply@github.com>2016-09-01 10:41:28 +0200
commitf90bf565a529d0e95155992a3c243952183f25a5 (patch)
tree151f8d8d79dba64a96d12b1c4a9c4fa38269dcf8 /src/reflect
parent45edf8699f76faa5d1b035fb8f887621bcbb9934 (diff)
parent743f0d2c2a33bc8ab0c1f7bee796865672ba2fcc (diff)
downloadscala-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')
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala5
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala1
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala22
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala20
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala4
-rw-r--r--src/reflect/scala/reflect/internal/transform/Erasure.scala52
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala3
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