summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/api/BuildUtils.scala17
-rw-r--r--src/reflect/scala/reflect/api/Importers.scala2
-rw-r--r--src/reflect/scala/reflect/api/Trees.scala2
-rw-r--r--src/reflect/scala/reflect/internal/BuildUtils.scala181
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala19
-rw-r--r--src/reflect/scala/reflect/internal/FreshNames.scala8
-rw-r--r--src/reflect/scala/reflect/internal/Importers.scala3
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala36
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala147
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala12
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala12
-rw-r--r--src/reflect/scala/reflect/macros/Evals.scala6
-rw-r--r--src/reflect/scala/reflect/macros/Typers.scala6
-rw-r--r--src/reflect/scala/reflect/macros/Universe.scala5
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala44
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala3
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolLoaders.scala5
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolTable.scala15
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala117
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedTypes.scala7
20 files changed, 452 insertions, 195 deletions
diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala
index 3bcf751ace..ec20a89a10 100644
--- a/src/reflect/scala/reflect/api/BuildUtils.scala
+++ b/src/reflect/scala/reflect/api/BuildUtils.scala
@@ -198,9 +198,9 @@ private[reflect] trait BuildUtils { self: Universe =>
val SyntacticFunction: SyntacticFunctionExtractor
trait SyntacticFunctionExtractor {
- def apply(params: List[Tree], body: Tree): Tree
+ def apply(params: List[Tree], body: Tree): Function
- def unapply(tree: Tree): Option[(List[ValDef], Tree)]
+ def unapply(tree: Function): Option[(List[ValDef], Tree)]
}
val SyntacticDefDef: SyntacticDefDefExtractor
@@ -248,6 +248,13 @@ private[reflect] trait BuildUtils { self: Universe =>
def unapply(tree: Tree): Option[(Tree)]
}
+ val SyntacticEmptyTypeTree: SyntacticEmptyTypeTreeExtractor
+
+ trait SyntacticEmptyTypeTreeExtractor {
+ def apply(): TypeTree
+ def unapply(tt: TypeTree): Boolean
+ }
+
val SyntacticFor: SyntacticForExtractor
val SyntacticForYield: SyntacticForExtractor
@@ -283,5 +290,11 @@ private[reflect] trait BuildUtils { self: Universe =>
def apply(name: Name, isBackquoted: Boolean = false): Ident
def unapply(tree: Ident): Option[(Name, Boolean)]
}
+
+ val SyntacticImport: SyntacticImportExtractor
+ trait SyntacticImportExtractor {
+ def apply(expr: Tree, selectors: List[Tree]): Import
+ def unapply(imp: Import): Some[(Tree, List[Tree])]
+ }
}
}
diff --git a/src/reflect/scala/reflect/api/Importers.scala b/src/reflect/scala/reflect/api/Importers.scala
index 5667d93e29..6539137cee 100644
--- a/src/reflect/scala/reflect/api/Importers.scala
+++ b/src/reflect/scala/reflect/api/Importers.scala
@@ -52,7 +52,7 @@ package api
* val imported = importer.importTree(tree)
*
* // after the tree is imported, it can be evaluated as usual
- * val tree = toolBox.resetAllAttrs(imported.duplicate)
+ * val tree = toolBox.untypecheck(imported.duplicate)
* val valueOfX = toolBox.eval(imported).asInstanceOf[T]
* ...
* }
diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala
index 83da5141b9..60e00ca5fd 100644
--- a/src/reflect/scala/reflect/api/Trees.scala
+++ b/src/reflect/scala/reflect/api/Trees.scala
@@ -1066,7 +1066,7 @@ trait Trees { self: Universe =>
* UnApply(
* // a dummy node that carries the type of unapplication to patmat
* // the <unapply-selector> here doesn't have an underlying symbol
- * // it only has a type assigned, therefore after `resetAllAttrs` this tree is no longer typeable
+ * // it only has a type assigned, therefore after `untypecheck` this tree is no longer typeable
* Apply(Select(Ident(Foo), newTermName("unapply")), List(Ident(newTermName("<unapply-selector>")))),
* // arguments of the unapply => nothing synthetic here
* List(Bind(newTermName("x"), Ident(nme.WILDCARD)))),
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala
index 6106339324..c5581601de 100644
--- a/src/reflect/scala/reflect/internal/BuildUtils.scala
+++ b/src/reflect/scala/reflect/internal/BuildUtils.scala
@@ -33,19 +33,19 @@ trait BuildUtils { self: SymbolTable =>
}
def newFreeTerm(name: String, value: => Any, flags: Long = 0L, origin: String = null): FreeTermSymbol =
- newFreeTermSymbol(newTermName(name), value, flags, origin)
+ newFreeTermSymbol(newTermName(name), value, flags, origin).markFlagsCompleted(mask = AllFlags)
def newFreeType(name: String, flags: Long = 0L, origin: String = null): FreeTypeSymbol =
- newFreeTypeSymbol(newTypeName(name), flags, origin)
+ newFreeTypeSymbol(newTypeName(name), flags, origin).markFlagsCompleted(mask = AllFlags)
def newNestedSymbol(owner: Symbol, name: Name, pos: Position, flags: Long, isClass: Boolean): Symbol =
- owner.newNestedSymbol(name, pos, flags, isClass)
+ owner.newNestedSymbol(name, pos, flags, isClass).markFlagsCompleted(mask = AllFlags)
def setAnnotations[S <: Symbol](sym: S, annots: List[AnnotationInfo]): S =
sym.setAnnotations(annots)
def setTypeSignature[S <: Symbol](sym: S, tpe: Type): S =
- sym.setTypeSignature(tpe)
+ sym.setTypeSignature(tpe).markAllCompleted()
def This(sym: Symbol): Tree = self.This(sym)
@@ -143,7 +143,7 @@ trait BuildUtils { self: SymbolTable =>
def RefTree(qual: Tree, sym: Symbol) = self.RefTree(qual, sym.name) setSymbol sym
- def freshTermName(prefix: String): TermName = self.freshTermName(prefix)
+ def freshTermName(prefix: String = nme.FRESH_TERM_NAME_PREFIX): TermName = self.freshTermName(prefix)
def freshTypeName(prefix: String): TypeName = self.freshTypeName(prefix)
@@ -435,16 +435,13 @@ trait BuildUtils { self: SymbolTable =>
}
object SyntacticFunction extends SyntacticFunctionExtractor {
- def apply(params: List[Tree], body: Tree): Tree = {
+ def apply(params: List[Tree], body: Tree): Function = {
val params0 :: Nil = mkParam(params :: Nil, PARAM)
require(params0.forall { _.rhs.isEmpty }, "anonymous functions don't support parameters with default values")
Function(params0, body)
}
- def unapply(tree: Tree): Option[(List[ValDef], Tree)] = tree match {
- case Function(params, body) => Some((params, body))
- case _ => None
- }
+ def unapply(tree: Function): Option[(List[ValDef], Tree)] = Function.unapply(tree)
}
object SyntacticNew extends SyntacticNewExtractor {
@@ -537,13 +534,15 @@ trait BuildUtils { self: SymbolTable =>
def unapply(tree: Tree): Option[Tree] = gen.Filter.unapply(tree)
}
- // abstract over possible alternative representations of no type in valdef
- protected object EmptyTypTree {
- def unapply(tree: Tree): Boolean = tree match {
- case EmptyTree => true
- case tt: TypeTree if (tt.original == null || tt.original.isEmpty) => true
- case _ => false
- }
+ // If a tree in type position isn't provided by the user (e.g. `tpt` fields of
+ // `ValDef` and `DefDef`, function params etc), then it's going to be parsed as
+ // TypeTree with empty original and empty tpe. This extractor matches such trees
+ // so that one can write q"val x = 2" to match typecheck(q"val x = 2"). Note that
+ // TypeTree() is the only possible representation for empty trees in type positions.
+ // We used to sometimes receive EmptyTree in such cases, but not anymore.
+ object SyntacticEmptyTypeTree extends SyntacticEmptyTypeTreeExtractor {
+ def apply(): TypeTree = self.TypeTree()
+ def unapply(tt: TypeTree): Boolean = tt.original == null || tt.original.isEmpty
}
// match a sequence of desugared `val $pat = $value`
@@ -561,8 +560,8 @@ trait BuildUtils { self: SymbolTable =>
case ValDef(_, name1, _, Match(MaybeUnchecked(value), CaseDef(pat, EmptyTree, Ident(name2)) :: Nil)) :: UnPatSeq(rest)
if name1 == name2 =>
Some((pat, value) :: rest)
- // case q"${_} val $name: ${EmptyTypTree()} = $value" :: UnPatSeq(rest) =>
- case ValDef(_, name, EmptyTypTree(), value) :: UnPatSeq(rest) =>
+ // case q"${_} val $name: ${SyntacticEmptyTypeTree()} = $value" :: UnPatSeq(rest) =>
+ case ValDef(_, name, SyntacticEmptyTypeTree(), value) :: UnPatSeq(rest) =>
Some((Bind(name, self.Ident(nme.WILDCARD)), value) :: rest)
// case q"${_} val $name: $tpt = $value" :: UnPatSeq(rest) =>
case ValDef(_, name, tpt, value) :: UnPatSeq(rest) =>
@@ -604,8 +603,8 @@ trait BuildUtils { self: SymbolTable =>
def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
case Function(ValDef(Modifiers(PARAM, _, _), name, tpt, EmptyTree) :: Nil, body) =>
tpt match {
- case EmptyTypTree() => Some((Bind(name, self.Ident(nme.WILDCARD)), body))
- case _ => Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), body))
+ case SyntacticEmptyTypeTree() => Some((Bind(name, self.Ident(nme.WILDCARD)), body))
+ case _ => Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), body))
}
case UnVisitor(_, CaseDef(pat, EmptyTree, body) :: Nil) =>
Some((pat, body))
@@ -770,6 +769,146 @@ trait BuildUtils { self: SymbolTable =>
}
def unapply(tree: Ident): Some[(Name, Boolean)] = Some((tree.name, tree.hasAttachment[BackquotedIdentifierAttachment.type]))
}
+
+ /** Facade over Imports and ImportSelectors that lets to structurally
+ * deconstruct/reconstruct them.
+ *
+ * Selectors are represented in the following way:
+ * 1. q"import foo._" <==> q"import foo.${pq"_"}"
+ * 2. q"import foo.bar" <==> q"import foo.${pq"bar"}"
+ * 3. q"import foo.{bar => baz}" <==> q"import foo.${pq"bar -> baz"}"
+ * 4. q"import foo.{bar => _}" <==> q"import foo.${pq"bar -> _"}"
+ *
+ * All names in selectors are TermNames despite the fact ImportSelector
+ * can theoretically contain TypeNames too (but they never do in practice.)
+ */
+ object SyntacticImport extends SyntacticImportExtractor {
+ // construct/deconstruct {_} import selector
+ private object WildcardSelector {
+ def apply(offset: Int): ImportSelector = ImportSelector(nme.WILDCARD, offset, null, -1)
+ def unapply(sel: ImportSelector): Option[Int] = sel match {
+ case ImportSelector(nme.WILDCARD, offset, null, -1) => Some(offset)
+ case _ => None
+ }
+ }
+
+ // construct/deconstruct {foo} import selector
+ private object NameSelector {
+ def apply(name: TermName, offset: Int): ImportSelector = ImportSelector(name, offset, name, offset)
+ def unapply(sel: ImportSelector): Option[(TermName, Int)] = sel match {
+ case ImportSelector(name1, offset1, name2, offset2) if name1 == name2 && offset1 == offset2 =>
+ Some((name1.toTermName, offset1))
+ case _ =>
+ None
+ }
+ }
+
+ // construct/deconstruct {foo => bar} import selector
+ private object RenameSelector {
+ def apply(name1: TermName, offset1: Int, name2: TermName, offset2: Int): ImportSelector =
+ ImportSelector(name1, offset1, name2, offset2)
+ def unapply(sel: ImportSelector): Option[(TermName, Int, TermName, Int)] = sel match {
+ case ImportSelector(_, _, null | nme.WILDCARD, _) =>
+ None
+ case ImportSelector(name1, offset1, name2, offset2) if name1 != name2 =>
+ Some((name1.toTermName, offset1, name2.toTermName, offset2))
+ case _ =>
+ None
+ }
+ }
+
+ // construct/deconstruct {foo => _} import selector
+ private object UnimportSelector {
+ def apply(name: TermName, offset: Int): ImportSelector =
+ ImportSelector(name, offset, nme.WILDCARD, -1)
+ def unapply(sel: ImportSelector): Option[(TermName, Int)] = sel match {
+ case ImportSelector(name, offset, nme.WILDCARD, _) => Some((name.toTermName, offset))
+ case _ => None
+ }
+ }
+
+ // represent {_} import selector as pq"_"
+ private object WildcardSelectorRepr {
+ def apply(pos: Position): Tree = atPos(pos)(self.Ident(nme.WILDCARD))
+ def unapply(tree: Tree): Option[Position] = tree match {
+ case self.Ident(nme.WILDCARD) => Some(tree.pos)
+ case _ => None
+ }
+ }
+
+ // represent {foo} import selector as pq"foo"
+ private object NameSelectorRepr {
+ def apply(name: TermName, pos: Position): Tree = atPos(pos)(Bind(name, WildcardSelectorRepr(pos)))
+ def unapply(tree: Tree): Option[(TermName, Position)] = tree match {
+ case Bind(name, WildcardSelectorRepr(_)) => Some((name.toTermName, tree.pos))
+ case _ => None
+ }
+ }
+
+ // pq"left -> right"
+ private object Arrow {
+ def apply(left: Tree, right: Tree): Apply =
+ Apply(self.Ident(nme.MINGT), left :: right :: Nil)
+ def unapply(tree: Apply): Option[(Tree, Tree)] = tree match {
+ case Apply(self.Ident(nme.MINGT), left :: right :: Nil) => Some((left, right))
+ case _ => None
+ }
+ }
+
+ // represent {foo => bar} import selector as pq"foo -> bar"
+ private object RenameSelectorRepr {
+ def apply(name1: TermName, pos1: Position, name2: TermName, pos2: Position): Tree = {
+ val left = NameSelectorRepr(name1, pos1)
+ val right = NameSelectorRepr(name2, pos2)
+ atPos(wrappingPos(left :: right :: Nil))(Arrow(left, right))
+ }
+ def unapply(tree: Tree): Option[(TermName, Position, TermName, Position)] = tree match {
+ case Arrow(NameSelectorRepr(name1, pos1), NameSelectorRepr(name2, pos2)) =>
+ Some((name1.toTermName, pos1, name2.toTermName, pos2))
+ case _ =>
+ None
+ }
+ }
+
+ // represent {foo => _} import selector as pq"foo -> _"
+ private object UnimportSelectorRepr {
+ def apply(name: TermName, pos: Position): Tree =
+ atPos(pos)(Arrow(NameSelectorRepr(name, pos), WildcardSelectorRepr(pos)))
+ def unapply(tree: Tree): Option[(TermName, Position)] = tree match {
+ case Arrow(NameSelectorRepr(name, pos), WildcardSelectorRepr(_)) =>
+ Some((name, pos))
+ case _ =>
+ None
+ }
+ }
+
+ private def derivedPos(t: Tree, offset: Int): Position =
+ if (t.pos == NoPosition) NoPosition else t.pos.withPoint(offset)
+
+ private def derivedOffset(pos: Position): Int =
+ if (pos == NoPosition) -1 else pos.point
+
+ def apply(expr: Tree, selectors: List[Tree]): Import = {
+ val importSelectors = selectors.map {
+ case WildcardSelectorRepr(pos) => WildcardSelector(derivedOffset(pos))
+ case NameSelectorRepr(name, pos) => NameSelector(name, derivedOffset(pos))
+ case RenameSelectorRepr(name1, pos1, name2, pos2) => RenameSelector(name1, derivedOffset(pos1), name2, derivedOffset(pos2))
+ case UnimportSelectorRepr(name, pos) => UnimportSelector(name, derivedOffset(pos))
+ case tree => throw new IllegalArgumentException(s"${showRaw(tree)} doesn't correspond to import selector")
+ }
+ Import(expr, importSelectors)
+ }
+
+ def unapply(imp: Import): Some[(Tree, List[Tree])] = {
+ val selectors = imp.selectors.map {
+ case WildcardSelector(offset) => WildcardSelectorRepr(derivedPos(imp, offset))
+ case NameSelector(name, offset) => NameSelectorRepr(name, derivedPos(imp, offset))
+ case RenameSelector(name1, offset1, name2, offset2) => RenameSelectorRepr(name1, derivedPos(imp, offset1), name2, derivedPos(imp, offset2))
+ case UnimportSelector(name, offset) => UnimportSelectorRepr(name, derivedPos(imp, offset))
+ }
+ Some((imp.expr, selectors))
+ }
+ }
}
val build: BuildImpl = new BuildImpl
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 4d24f0b219..7a0c70caf6 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -30,12 +30,12 @@ trait Definitions extends api.StandardDefinitions {
private def enterNewClass(owner: Symbol, name: TypeName, parents: List[Type], flags: Long = 0L): ClassSymbol = {
val clazz = owner.newClassSymbol(name, NoPosition, flags)
- clazz setInfoAndEnter ClassInfoType(parents, newScope, clazz)
+ clazz setInfoAndEnter ClassInfoType(parents, newScope, clazz) markAllCompleted
}
private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long): MethodSymbol = {
val msym = owner.newMethod(name.encode, NoPosition, flags)
val params = msym.newSyntheticValueParams(formals)
- msym setInfo MethodType(params, restpe)
+ msym setInfo MethodType(params, restpe) markAllCompleted
}
private def enterNewMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): MethodSymbol =
owner.info.decls enter newMethod(owner, name, formals, restpe, flags)
@@ -251,8 +251,8 @@ trait Definitions extends api.StandardDefinitions {
}
// top types
- lazy val AnyClass = enterNewClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT)
- lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectTpe)
+ lazy val AnyClass = enterNewClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT) markAllCompleted
+ lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectTpe) markAllCompleted
lazy val ObjectClass = getRequiredClass(sn.Object.toString)
// Cached types for core monomorphic classes
@@ -275,7 +275,7 @@ trait Definitions extends api.StandardDefinitions {
val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, AnyTpe :: Nil, ABSTRACT)
val av_constr = anyval.newClassConstructor(NoPosition)
anyval.info.decls enter av_constr
- anyval
+ anyval markAllCompleted
}).asInstanceOf[ClassSymbol]
def AnyVal_getClass = getMemberMethod(AnyValClass, nme.getClass_)
@@ -287,8 +287,10 @@ trait Definitions extends api.StandardDefinitions {
locally {
this initFlags ABSTRACT | FINAL
this setInfoAndEnter ClassInfoType(List(parent.tpe), newScope, this)
+ this markAllCompleted
}
final override def isBottomClass = true
+ final override def isThreadsafe(purpose: SymbolOps): Boolean = true
}
final object NothingClass extends BottomClassSymbol(tpnme.Nothing, AnyClass) {
override def isSubClass(that: Symbol) = true
@@ -357,7 +359,7 @@ trait Definitions extends api.StandardDefinitions {
def delayedInitMethod = getMemberMethod(DelayedInitClass, nme.delayedInit)
lazy val TypeConstraintClass = requiredClass[scala.annotation.TypeConstraint]
- lazy val SingletonClass = enterNewClass(ScalaPackageClass, tpnme.Singleton, AnyTpe :: Nil, ABSTRACT | TRAIT | FINAL)
+ lazy val SingletonClass = enterNewClass(ScalaPackageClass, tpnme.Singleton, AnyTpe :: Nil, ABSTRACT | TRAIT | FINAL) markAllCompleted
lazy val SerializableClass = requiredClass[scala.Serializable]
lazy val JavaSerializableClass = requiredClass[java.io.Serializable] modifyInfo fixupAsAnyTrait
lazy val ComparableClass = requiredClass[java.lang.Comparable[_]] modifyInfo fixupAsAnyTrait
@@ -1127,6 +1129,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val AnnotationDefaultAttr: ClassSymbol = {
val sym = RuntimePackageClass.newClassSymbol(tpnme.AnnotationDefaultATTR, NoPosition, 0L)
sym setInfo ClassInfoType(List(AnnotationClass.tpe), newScope, sym)
+ markAllCompleted(sym)
RuntimePackageClass.info.decls.toList.filter(_.name == sym.name) match {
case existing :: _ =>
existing.asInstanceOf[ClassSymbol]
@@ -1226,7 +1229,7 @@ trait Definitions extends api.StandardDefinitions {
val tparam = clazz.newSyntheticTypeParam("T0", flags)
val parents = List(AnyRefTpe, parentFn(tparam))
- clazz setInfo GenPolyType(List(tparam), ClassInfoType(parents, newScope, clazz))
+ clazz setInfo GenPolyType(List(tparam), ClassInfoType(parents, newScope, clazz)) markAllCompleted
}
def newPolyMethod(typeParamCount: Int, owner: Symbol, name: TermName, flags: Long)(createFn: PolyMethodCreator): MethodSymbol = {
@@ -1237,7 +1240,7 @@ trait Definitions extends api.StandardDefinitions {
case (_, restpe) => NullaryMethodType(restpe)
}
- msym setInfoAndEnter genPolyType(tparams, mtpe)
+ msym setInfoAndEnter genPolyType(tparams, mtpe) markAllCompleted
}
/** T1 means one type parameter.
diff --git a/src/reflect/scala/reflect/internal/FreshNames.scala b/src/reflect/scala/reflect/internal/FreshNames.scala
index 1de8d425ad..7e9a568266 100644
--- a/src/reflect/scala/reflect/internal/FreshNames.scala
+++ b/src/reflect/scala/reflect/internal/FreshNames.scala
@@ -8,7 +8,7 @@ package internal
import scala.reflect.internal.util.FreshNameCreator
-trait FreshNames { self: Names =>
+trait FreshNames { self: Names with StdNames =>
// SI-6879 Keeps track of counters that are supposed to be globally unique
// as opposed to traditional freshers that are unique to compilation units.
val globalFreshNameCreator = new FreshNameCreator
@@ -17,8 +17,8 @@ trait FreshNames { self: Names =>
def currentFreshNameCreator: FreshNameCreator
// create fresh term/type name using implicit fresh name creator
- def freshTermName(prefix: String = "x$")(implicit creator: FreshNameCreator): TermName = newTermName(creator.newName(prefix))
- def freshTypeName(prefix: String)(implicit creator: FreshNameCreator): TypeName = newTypeName(creator.newName(prefix))
+ def freshTermName(prefix: String = nme.FRESH_TERM_NAME_PREFIX)(implicit creator: FreshNameCreator): TermName = newTermName(creator.newName(prefix))
+ def freshTypeName(prefix: String)(implicit creator: FreshNameCreator): TypeName = newTypeName(creator.newName(prefix))
// Extractor that matches names which were generated by some
// FreshNameCreator with known prefix. Extracts user-specified
@@ -36,4 +36,4 @@ trait FreshNames { self: Names =>
else Some(NameTransformer.decode(sname.replaceFirst(quotedCreatorPrefix, "").replaceAll("\\d*$", "")))
}
}
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala
index 483d0dd656..ff91b08ea1 100644
--- a/src/reflect/scala/reflect/internal/Importers.scala
+++ b/src/reflect/scala/reflect/internal/Importers.scala
@@ -4,6 +4,7 @@ package internal
import scala.collection.mutable.WeakHashMap
import scala.ref.WeakReference
+import scala.reflect.internal.Flags._
// SI-6241: move importers to a mirror
trait Importers extends api.Importers { to: SymbolTable =>
@@ -87,6 +88,7 @@ trait Importers extends api.Importers { to: SymbolTable =>
}
my setInfo GenPolyType(mytypeParams, importType(theirCore))
my setAnnotations (their.annotations map importAnnotationInfo)
+ markAllCompleted(my)
}
}
} finally {
@@ -142,6 +144,7 @@ trait Importers extends api.Importers { to: SymbolTable =>
myowner.newTypeSymbol(myname.toTypeName, mypos, myflags)
}
symMap.weakUpdate(their, my)
+ markFlagsCompleted(my)(mask = AllFlags)
my setInfo recreatedSymbolCompleter(my, their)
}
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 53475be479..679186f938 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -295,22 +295,23 @@ trait StdNames {
protected implicit def createNameType(name: String): TermName = newTermNameCached(name)
/** Base strings from which synthetic names are derived. */
- val BITMAP_PREFIX = "bitmap$"
- val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$"
- val DEFAULT_GETTER_STRING = "$default$"
- val DEFAULT_GETTER_INIT_STRING = NameTransformer.encode("<init>") + DEFAULT_GETTER_STRING
- val DO_WHILE_PREFIX = "doWhile$"
- val EVIDENCE_PARAM_PREFIX = "evidence$"
- val EXCEPTION_RESULT_PREFIX = "exceptionResult"
- val EXPAND_SEPARATOR_STRING = "$$"
- val INTERPRETER_IMPORT_WRAPPER = "$iw"
- val LOCALDUMMY_PREFIX = "<local " // owner of local blocks
- val PROTECTED_PREFIX = "protected$"
- val PROTECTED_SET_PREFIX = PROTECTED_PREFIX + "set"
- val SUPER_PREFIX_STRING = "super$"
- val WHILE_PREFIX = "while$"
- val FRESH_PREFIX = "fresh"
- val FRESH_SUFFIX = "macro$" // uses a keyword to avoid collisions with mangled names
+ val BITMAP_PREFIX = "bitmap$"
+ val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$"
+ val DEFAULT_GETTER_STRING = "$default$"
+ val DEFAULT_GETTER_INIT_STRING = NameTransformer.encode("<init>") + DEFAULT_GETTER_STRING
+ val DO_WHILE_PREFIX = "doWhile$"
+ val EVIDENCE_PARAM_PREFIX = "evidence$"
+ val EXCEPTION_RESULT_PREFIX = "exceptionResult"
+ val EXPAND_SEPARATOR_STRING = "$$"
+ val FRESH_TERM_NAME_PREFIX = "x$"
+ val INTERPRETER_IMPORT_WRAPPER = "$iw"
+ val LOCALDUMMY_PREFIX = "<local " // owner of local blocks
+ val PROTECTED_PREFIX = "protected$"
+ val PROTECTED_SET_PREFIX = PROTECTED_PREFIX + "set"
+ val SUPER_PREFIX_STRING = "super$"
+ val WHILE_PREFIX = "while$"
+ val FRESH_PREFIX = "fresh"
+ val FRESH_SUFFIX = "macro$" // uses a keyword to avoid collisions with mangled names
// Compiler internal names
val ANYname: NameType = "<anyname>"
@@ -602,12 +603,14 @@ trait StdNames {
val SyntacticBlock: NameType = "SyntacticBlock"
val SyntacticClassDef: NameType = "SyntacticClassDef"
val SyntacticDefDef: NameType = "SyntacticDefDef"
+ val SyntacticEmptyTypeTree: NameType = "SyntacticEmptyTypeTree"
val SyntacticFilter: NameType = "SyntacticFilter"
val SyntacticFor: NameType = "SyntacticFor"
val SyntacticForYield: NameType = "SyntacticForYield"
val SyntacticFunction: NameType = "SyntacticFunction"
val SyntacticFunctionType: NameType = "SyntacticFunctionType"
val SyntacticIdent: NameType = "SyntacticIdent"
+ val SyntacticImport: NameType = "SyntacticImport"
val SyntacticMatch: NameType = "SyntacticMatch"
val SyntacticNew: NameType = "SyntacticNew"
val SyntacticObjectDef: NameType = "SyntacticObjectDef"
@@ -838,6 +841,7 @@ trait StdNames {
val LSR = encode(">>>")
val LT = encode("<")
val MINUS = encode("-")
+ val MINGT = encode("->")
val MOD = encode("%")
val MUL = encode("*")
val NE = encode("!=")
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index b8cd1e86d3..2969bd92de 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -55,16 +55,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def newFreeTypeSymbol(name: TypeName, flags: Long = 0L, origin: String): FreeTypeSymbol =
new FreeTypeSymbol(name, origin) initFlags flags
- /** Determines whether the given information request should trigger the given symbol's completer.
- * See comments to `Symbol.needsInitialize` for details.
- */
- protected def shouldTriggerCompleter(symbol: Symbol, completer: Type, isFlagRelated: Boolean, mask: Long) =
- completer match {
- case null => false
- case _: FlagAgnosticCompleter => !isFlagRelated
- case _ => abort(s"unsupported completer: $completer of class ${if (completer != null) completer.getClass else null} for symbol ${symbol.fullName}")
- }
-
/** The original owner of a class. Used by the backend to generate
* EnclosingMethod attributes.
*/
@@ -106,18 +96,27 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
def knownDirectSubclasses = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize
+ // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
+ if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize
children
}
def selfType = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize
+ // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
+ if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize
typeOfThis
}
def baseClasses = info.baseClasses
def module = sourceModule
def thisPrefix: Type = thisType
+
+ // automatic full initialization on access to info from reflection API is a double-edged sword
+ // on the one hand, it's convenient so that the users don't have to deal with initialization themselves before printing out stuff
+ // (e.g. printing out a method's signature without fully initializing it would result in <_>'s for parameters
+ // on the other hand, this strategy can potentially cause unexpected effects due to being inconsistent with compiler's behavior
+ // so far I think user convenience outweighs the scariness, but we need to keep the tradeoff in mind
+ // NOTE: if you end up removing the call to fullyInitializeSymbol, consider that it would affect both runtime reflection and macros
def typeSignature: Type = { fullyInitializeSymbol(this); info }
def typeSignatureIn(site: Type): Type = { fullyInitializeSymbol(this); site memberInfo this }
@@ -140,6 +139,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
with Annotatable[Symbol]
with Attachable {
+ // makes sure that all symbols that runtime reflection deals with are synchronized
+ private def isSynchronized = this.isInstanceOf[scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol]
+ private def isAprioriThreadsafe = isThreadsafe(AllOps)
+ assert(isCompilerUniverse || isSynchronized || isAprioriThreadsafe, s"unsafe symbol $initName (child of $initOwner) in runtime reflection universe")
+
type AccessBoundaryType = Symbol
type AnnotationType = AnnotationInfo
@@ -609,20 +613,55 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
&& isTopLevel
&& nme.isReplWrapperName(name)
)
+
+ /** In our current architecture, symbols for top-level classes and modules
+ * are created as dummies. Package symbols just call newClass(name) or newModule(name) and
+ * consider their job done.
+ *
+ * In order for such a dummy to provide meaningful info (e.g. a list of its members),
+ * it needs to go through unpickling. Unpickling is a process of reading Scala metadata
+ * from ScalaSignature annotations and assigning it to symbols and types.
+ *
+ * A single unpickling session takes a top-level class or module, parses the ScalaSignature annotation
+ * and then reads metadata for the unpicklee, its companion (if any) and all their members recursively
+ * (i.e. the pickle not only contains info about directly nested classes/modules, but also about
+ * classes/modules nested into those and so on).
+ *
+ * Unpickling is triggered automatically whenever typeSignature (info in compiler parlance) is called.
+ * This happens because package symbols assign completer thunks to the dummies they create.
+ * Therefore metadata loading happens lazily and transparently.
+ *
+ * Almost transparently. Unfortunately metadata isn't limited to just signatures (i.e. lists of members).
+ * It also includes flags (which determine e.g. whether a class is sealed or not), annotations and privateWithin.
+ * This gives rise to unpleasant effects like in SI-6277, when a flag test called on an uninitialize symbol
+ * produces incorrect results.
+ *
+ * One might think that the solution is simple: automatically call the completer
+ * whenever one needs flags, annotations and privateWithin - just like it's done for typeSignature.
+ * Unfortunately, this leads to weird crashes in scalac, and currently we can't attempt
+ * to fix the core of the compiler risk stability a few weeks before the final release.
+ * upd. Haha, "a few weeks before the final release". This surely sounds familiar :)
+ *
+ * However we do need to fix this for runtime reflection, since this idionsynchrazy is not something
+ * we'd like to expose to reflection users. Therefore a proposed solution is to check whether we're in a
+ * runtime reflection universe, and if yes and if we've not yet loaded the requested info, then to commence initialization.
+ */
final def getFlag(mask: Long): Long = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = true, mask = mask)) initialize
+ if (!isCompilerUniverse && !isThreadsafe(purpose = FlagOps(mask))) initialize
flags & mask
}
/** Does symbol have ANY flag in `mask` set? */
final def hasFlag(mask: Long): Boolean = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = true, mask = mask)) initialize
+ // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
+ if (!isCompilerUniverse && !isThreadsafe(purpose = FlagOps(mask))) initialize
(flags & mask) != 0
}
def hasFlag(mask: Int): Boolean = hasFlag(mask.toLong)
/** Does symbol have ALL the flags in `mask` set? */
final def hasAllFlags(mask: Long): Boolean = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = true, mask = mask)) initialize
+ // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
+ if (!isCompilerUniverse && !isThreadsafe(purpose = FlagOps(mask))) initialize
(flags & mask) == mask
}
@@ -789,7 +828,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*
* Stability and volatility are checked separately to allow volatile paths in patterns that amount to equality checks. SI-6815
*/
- def isStable = isTerm && !isMutable && !(hasFlag(BYNAMEPARAM)) && (!isMethod || hasStableFlag)
+ final def isStable = isTerm && !isMutable && !(hasFlag(BYNAMEPARAM)) && (!isMethod || hasStableFlag)
final def hasVolatileType = tpe.isVolatile && !hasAnnotation(uncheckedStableClass)
/** Does this symbol denote the primary constructor of its enclosing class? */
@@ -943,12 +982,21 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isInitialized: Boolean =
validTo != NoPeriod
- /** Some completers call sym.setInfo when still in-flight and then proceed with initialization (e.g. see LazyPackageType)
- * setInfo sets _validTo to current period, which means that after a call to setInfo isInitialized will start returning true.
- * Unfortunately, this doesn't mean that info becomes ready to be used, because subsequent initialization might change the info.
- * Therefore we need this method to distinguish between initialized and really initialized symbol states.
+ /** We consider a symbol to be thread-safe, when multiple concurrent threads can call its methods
+ * (either directly or indirectly via public reflection or internal compiler infrastructure),
+ * without any locking and everything works as it should work.
+ *
+ * In its basic form, `isThreadsafe` always returns false. Runtime reflection augments reflection infrastructure
+ * with threadsafety-tracking mechanism implemented in `SynchronizedSymbol` that communicates with underlying completers
+ * and can sometimes return true if the symbol has been completed to the point of thread safety.
+ *
+ * The `purpose` parameter signifies whether we want to just check immutability of certain flags for the given mask.
+ * This is necessary to enable robust auto-initialization of `Symbol.flags` for runtime reflection, and is also quite handy
+ * in avoiding unnecessary initializations when requesting for flags that have already been set.
*/
- final def isFullyInitialized: Boolean = _validTo != NoPeriod && (flags & LOCKED) == 0
+ def isThreadsafe(purpose: SymbolOps): Boolean = false
+ def markFlagsCompleted(mask: Long): this.type = this
+ def markAllCompleted(): this.type = this
/** Can this symbol be loaded by a reflective mirror?
*
@@ -1225,7 +1273,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
private[this] var _privateWithin: Symbol = _
def privateWithin = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize
+ // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
+ if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize
_privateWithin
}
def privateWithin_=(sym: Symbol) { _privateWithin = sym }
@@ -1483,46 +1532,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
catch { case _: CyclicReference => debuglog("Hit cycle in maybeInitialize of $this") ; false }
}
- /** Called when the programmer requests information that might require initialization of the underlying symbol.
- *
- * `isFlagRelated` and `mask` describe the nature of this information.
- * isFlagRelated = true means that the programmer needs particular bits in flags.
- * isFlagRelated = false means that the request is unrelated to flags (annotations or privateWithin).
- *
- * In our current architecture, symbols for top-level classes and modules
- * are created as dummies. Package symbols just call newClass(name) or newModule(name) and
- * consider their job done.
- *
- * In order for such a dummy to provide meaningful info (e.g. a list of its members),
- * it needs to go through unpickling. Unpickling is a process of reading Scala metadata
- * from ScalaSignature annotations and assigning it to symbols and types.
- *
- * A single unpickling session takes a top-level class or module, parses the ScalaSignature annotation
- * and then reads metadata for the unpicklee, its companion (if any) and all their members recursively
- * (i.e. the pickle not only contains info about directly nested classes/modules, but also about
- * classes/modules nested into those and so on).
- *
- * Unpickling is triggered automatically whenever typeSignature (info in compiler parlance) is called.
- * This happens because package symbols assign completer thunks to the dummies they create.
- * Therefore metadata loading happens lazily and transparently.
- *
- * Almost transparently. Unfortunately metadata isn't limited to just signatures (i.e. lists of members).
- * It also includes flags (which determine e.g. whether a class is sealed or not), annotations and privateWithin.
- * This gives rise to unpleasant effects like in SI-6277, when a flag test called on an uninitialize symbol
- * produces incorrect results.
- *
- * One might think that the solution is simple: automatically call the completer whenever one needs
- * flags, annotations and privateWithin - just like it's done for typeSignature. Unfortunately, this
- * leads to weird crashes in scalac, and currently we can't attempt to fix the core of the compiler
- * risk stability a few weeks before the final release.
- *
- * However we do need to fix this for runtime reflection, since it's not something we'd like to
- * expose to reflection users. Therefore a proposed solution is to check whether we're in a
- * runtime reflection universe and if yes then to commence initialization.
- */
- protected def needsInitialize(isFlagRelated: Boolean, mask: Long) =
- !isInitialized && (flags & LOCKED) == 0 && shouldTriggerCompleter(this, if (infos ne null) infos.info else null, isFlagRelated, mask)
-
/** Was symbol's type updated during given phase? */
final def hasTypeAt(pid: Phase#Id): Boolean = {
assert(isCompilerUniverse)
@@ -1681,7 +1690,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* the annotations attached to member a definition (class, method, type, field).
*/
def annotations: List[AnnotationInfo] = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize
+ // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
+ if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize
_annotations
}
@@ -3510,6 +3520,17 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
Statistics.newView("#symbols")(ids)
+
+// -------------- Completion --------------------------------------------------------
+
+ // is used to differentiate levels of thread-safety in `Symbol.isThreadsafe`
+ case class SymbolOps(isFlagRelated: Boolean, mask: Long)
+ val AllOps = SymbolOps(isFlagRelated = false, mask = 0L)
+ def FlagOps(mask: Long) = SymbolOps(isFlagRelated = true, mask = mask)
+
+ private def relevantSymbols(syms: Seq[Symbol]) = syms.flatMap(sym => List(sym, sym.moduleClass, sym.sourceModule))
+ def markFlagsCompleted(syms: Symbol*)(mask: Long): Unit = relevantSymbols(syms).foreach(_.markFlagsCompleted(mask))
+ def markAllCompleted(syms: Symbol*): Unit = relevantSymbols(syms).foreach(_.markAllCompleted)
}
object SymbolsStats {
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index ba7efc94a6..2d4e0b3b34 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -1969,12 +1969,12 @@ trait Types
def apply(value: Constant) = unique(new UniqueConstantType(value))
}
- private var _volatileRecursions: Int = 0
- def volatileRecursions = _volatileRecursions
- def volatileRecursions_=(value: Int) = _volatileRecursions = value
-
- private val _pendingVolatiles = new mutable.HashSet[Symbol]
- def pendingVolatiles = _pendingVolatiles
+ /* Syncnote: The `volatile` var and `pendingVolatiles` mutable set need not be protected
+ * with synchronized, because they are accessed only from isVolatile, which is called only from
+ * Typer.
+ */
+ private var volatileRecursions: Int = 0
+ private val pendingVolatiles = new mutable.HashSet[Symbol]
class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) {
require(args0 ne Nil, this)
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index 2a19441476..42f794736a 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -275,6 +275,7 @@ abstract class UnPickler {
def pflags = flags & PickledFlags
def finishSym(sym: Symbol): Symbol = {
+ markFlagsCompleted(sym)(mask = AllFlags)
sym.privateWithin = privateWithin
sym.info = (
if (atEnd) {
@@ -663,7 +664,7 @@ abstract class UnPickler {
private class LazyTypeRef(i: Int) extends LazyType with FlagAgnosticCompleter {
private val definedAtRunId = currentRunId
private val p = phase
- override def complete(sym: Symbol) : Unit = try {
+ protected def completeInternal(sym: Symbol) : Unit = try {
val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType`
if (p ne null)
slowButSafeEnteringPhase(p) (sym setInfo tp)
@@ -673,6 +674,10 @@ abstract class UnPickler {
catch {
case e: MissingRequirementError => throw toTypeError(e)
}
+ override def complete(sym: Symbol) : Unit = {
+ completeInternal(sym)
+ if (!isCompilerUniverse) markAllCompleted(sym)
+ }
override def load(sym: Symbol) { complete(sym) }
}
@@ -680,8 +685,9 @@ abstract class UnPickler {
* of completed symbol to symbol at index `j`.
*/
private class LazyTypeRefAndAlias(i: Int, j: Int) extends LazyTypeRef(i) {
- override def complete(sym: Symbol) = try {
- super.complete(sym)
+ override def completeInternal(sym: Symbol) = try {
+ super.completeInternal(sym)
+
var alias = at(j, readSymbol)
if (alias.isOverloaded)
alias = slowButSafeEnteringPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt))))
diff --git a/src/reflect/scala/reflect/macros/Evals.scala b/src/reflect/scala/reflect/macros/Evals.scala
index 222ae43d79..68e07dd319 100644
--- a/src/reflect/scala/reflect/macros/Evals.scala
+++ b/src/reflect/scala/reflect/macros/Evals.scala
@@ -17,13 +17,13 @@ trait Evals {
* permitted by the shape of the arguments.
*
* Known issues: because of [[https://issues.scala-lang.org/browse/SI-5748 https://issues.scala-lang.org/browse/SI-5748]]
- * trees being evaluated first need to undergo `resetAllAttrs`. Resetting symbols and types
+ * trees being evaluated first need to undergo `untypecheck`. Resetting symbols and types
* mutates the tree in place, therefore the conventional approach is to `duplicate` the tree first.
*
* {{{
* scala> def impl(c: Context)(x: c.Expr[String]) = {
- * | val x1 = c.Expr[String](c.resetAllAttrs(x.tree.duplicate))
- * | println(s"compile-time value is: \${c.eval(x1)}")
+ * | val x1 = c.Expr[String](c.untypecheck(x.tree.duplicate))
+ * | println(s"compile-time value is: ${c.eval(x1)}")
* | x
* | }
* impl: (c: Context)(x: c.Expr[String])c.Expr[String]
diff --git a/src/reflect/scala/reflect/macros/Typers.scala b/src/reflect/scala/reflect/macros/Typers.scala
index 87de442921..6c077de1d2 100644
--- a/src/reflect/scala/reflect/macros/Typers.scala
+++ b/src/reflect/scala/reflect/macros/Typers.scala
@@ -68,12 +68,6 @@ trait Typers {
*/
def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree
- /** Recursively resets symbols and types in a given tree.
- * WARNING: Don't use this API, go for [[untypecheck]] instead.
- */
- @deprecated("Use `c.untypecheck` instead", "2.11.0")
- def resetAllAttrs(tree: Tree): Tree
-
/** Recursively resets locally defined symbols and types in a given tree.
* WARNING: Don't use this API, go for [[untypecheck]] instead.
*/
diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala
index d84e6aa737..bc5c8b2840 100644
--- a/src/reflect/scala/reflect/macros/Universe.scala
+++ b/src/reflect/scala/reflect/macros/Universe.scala
@@ -122,7 +122,7 @@ abstract class Universe extends scala.reflect.api.Universe {
def setType(tp: Type): Tree
/** Like `setType`, but if this is a previously empty TypeTree that
- * fact is remembered so that resetAllAttrs will snap back.
+ * fact is remembered so that `untypecheck` will snap back.
*
* \@PP: Attempting to elaborate on the above, I find: If defineType
* is called on a TypeTree whose type field is null or NoType,
@@ -130,7 +130,8 @@ abstract class Universe extends scala.reflect.api.Universe {
* ResetAttrsTraverser, which nulls out the type field of TypeTrees
* for which wasEmpty is true, leaving the others alone.
*
- * resetAllAttrs is used in situations where some speculative
+ * `untypecheck` (or `resetAttrs` in compiler parlance) is used
+ * in situations where some speculative
* typing of a tree takes place, fails, and the tree needs to be
* returned to its former state to try again. So according to me:
* using `defineType` instead of `setType` is how you communicate
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 7cc5176507..68c67bb1f8 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -42,7 +42,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
// overriden by ReflectGlobal
def rootClassLoader: ClassLoader = this.getClass.getClassLoader
- trait JavaClassCompleter extends FlagAssigningCompleter
+ trait JavaClassCompleter
def runtimeMirror(cl: ClassLoader): Mirror = gilSynchronized {
mirrors get cl match {
@@ -63,10 +63,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
private[reflect] lazy val runDefinitions = new definitions.RunDefinitions // only one "run" in the reflection universe
import runDefinitions._
- override lazy val RootPackage = new RootPackage with SynchronizedTermSymbol
- override lazy val RootClass = new RootClass with SynchronizedModuleClassSymbol
- override lazy val EmptyPackage = new EmptyPackage with SynchronizedTermSymbol
- override lazy val EmptyPackageClass = new EmptyPackageClass with SynchronizedModuleClassSymbol
+ override lazy val RootPackage = (new RootPackage with SynchronizedTermSymbol).markFlagsCompleted(mask = AllFlags)
+ override lazy val RootClass = (new RootClass with SynchronizedModuleClassSymbol).markFlagsCompleted(mask = AllFlags)
+ override lazy val EmptyPackage = (new EmptyPackage with SynchronizedTermSymbol).markFlagsCompleted(mask = AllFlags)
+ override lazy val EmptyPackageClass = (new EmptyPackageClass with SynchronizedModuleClassSymbol).markFlagsCompleted(mask = AllFlags)
/** The lazy type for root.
*/
@@ -575,6 +575,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
val bytes = ssig.getBytes
val len = ByteCodecs.decode(bytes)
unpickler.unpickle(bytes take len, 0, clazz, module, jclazz.getName)
+ markAllCompleted(clazz, module)
case None =>
loadBytes[Array[String]]("scala.reflect.ScalaLongSignature") match {
case Some(slsig) =>
@@ -583,6 +584,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
val len = ByteCodecs.decode(encoded)
val decoded = encoded.take(len)
unpickler.unpickle(decoded, 0, clazz, module, jclazz.getName)
+ markAllCompleted(clazz, module)
case None =>
// class does not have a Scala signature; it's a Java class
info("translating reflection info for Java " + jclazz) //debug
@@ -605,6 +607,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
private def createTypeParameter(jtvar: jTypeVariable[_ <: GenericDeclaration]): TypeSymbol = {
val tparam = sOwner(jtvar).newTypeParameter(newTypeName(jtvar.getName))
.setInfo(new TypeParamCompleter(jtvar))
+ markFlagsCompleted(tparam)(mask = AllFlags)
tparamCache enter (jtvar, tparam)
tparam
}
@@ -617,6 +620,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
override def load(sym: Symbol) = complete(sym)
override def complete(sym: Symbol) = {
sym setInfo TypeBounds.upper(glb(jtvar.getBounds.toList map typeToScala map objToAny))
+ markAllCompleted(sym)
}
}
@@ -655,7 +659,16 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
* @param module The Scala companion object for which info is copied
* @param jclazz The Java class
*/
- private class FromJavaClassCompleter(clazz: Symbol, module: Symbol, jclazz: jClass[_]) extends LazyType with JavaClassCompleter with FlagAssigningCompleter {
+ private class FromJavaClassCompleter(clazz: Symbol, module: Symbol, jclazz: jClass[_]) extends LazyType with JavaClassCompleter with FlagAgnosticCompleter {
+ // one doesn't need to do non-trivial computations to assign flags for Java-based reflection artifacts
+ // therefore I'm moving flag-assigning logic from completion to construction
+ val flags = jclazz.scalaFlags
+ clazz setFlag (flags | JAVA)
+ if (module != NoSymbol) {
+ module setFlag (flags & PRIVATE | JAVA)
+ module.moduleClass setFlag (flags & PRIVATE | JAVA)
+ }
+ markFlagsCompleted(clazz, module)(mask = AllFlags)
/** used to avoid cycles while initializing classes */
private var parentsLevel = 0
@@ -665,12 +678,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
override def load(sym: Symbol): Unit = {
debugInfo("completing from Java " + sym + "/" + clazz.fullName)//debug
assert(sym == clazz || (module != NoSymbol && (sym == module || sym == module.moduleClass)), sym)
- val flags = jclazz.scalaFlags
- clazz setFlag (flags | JAVA)
- if (module != NoSymbol) {
- module setFlag (flags & PRIVATE | JAVA)
- module.moduleClass setFlag (flags & PRIVATE | JAVA)
- }
propagatePackageBoundary(jclazz, relatedSymbols: _*)
copyAnnotations(clazz, jclazz)
@@ -686,6 +693,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
override def complete(sym: Symbol): Unit = {
load(sym)
completeRest()
+ markAllCompleted(clazz, module)
}
def completeRest(): Unit = gilSynchronized {
@@ -738,6 +746,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
class LazyPolyType(override val typeParams: List[Symbol]) extends LazyType with FlagAgnosticCompleter {
override def complete(sym: Symbol) {
completeRest()
+ markAllCompleted(clazz, module)
}
}
}
@@ -892,6 +901,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
val pkg = owner.newPackage(name)
pkg.moduleClass setInfo new LazyPackageType
pkg setInfoAndEnter pkg.moduleClass.tpe
+ markFlagsCompleted(pkg)(mask = AllFlags)
info("made Scala "+pkg)
pkg
} else
@@ -1074,6 +1084,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
fieldCache.enter(jfield, field)
propagatePackageBoundary(jfield, field)
copyAnnotations(field, jfield)
+ markAllCompleted(field)
field
}
@@ -1100,11 +1111,9 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
setMethType(meth, tparams, paramtpes, resulttpe)
propagatePackageBoundary(jmeth.javaFlags, meth)
copyAnnotations(meth, jmeth)
-
- if (jmeth.javaFlags.isVarargs)
- meth modifyInfo arrayToRepeated
- else
- meth
+ if (jmeth.javaFlags.isVarargs) meth modifyInfo arrayToRepeated
+ markAllCompleted(meth)
+ meth
}
/**
@@ -1127,6 +1136,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
constr setInfo GenPolyType(tparams, MethodType(clazz.newSyntheticValueParams(paramtpes), clazz.tpe))
propagatePackageBoundary(jconstr.javaFlags, constr)
copyAnnotations(constr, jconstr)
+ markAllCompleted(constr)
constr
}
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index 8811b5513e..fb893cbff1 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -32,8 +32,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
// inaccessible: this._skolemizationLevel
// inaccessible: this._undoLog
// inaccessible: this._intersectionWitness
- // inaccessible: this._volatileRecursions
- // inaccessible: this._pendingVolatiles
// inaccessible: this._subsametypeRecursions
// inaccessible: this._pendingSubTypes
// inaccessible: this._basetypeRecursions
@@ -206,6 +204,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
this.NoSymbol
this.CyclicReference
// inaccessible: this.TypeHistory
+ this.SymbolOps
this.TermName
this.TypeName
this.Liftable
diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
index 30a3855d70..c56bc28d90 100644
--- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
@@ -6,6 +6,7 @@ import internal.Flags
import java.lang.{Class => jClass, Package => jPackage}
import scala.collection.mutable
import scala.reflect.runtime.ReflectionUtils.scalacShouldntLoadClass
+import scala.reflect.internal.Flags._
private[reflect] trait SymbolLoaders { self: SymbolTable =>
@@ -17,6 +18,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
* is found, a package is created instead.
*/
class TopClassCompleter(clazz: Symbol, module: Symbol) extends SymLoader with FlagAssigningCompleter {
+ markFlagsCompleted(clazz, module)(mask = ~TopLevelPickledFlags)
override def complete(sym: Symbol) = {
debugInfo("completing "+sym+"/"+clazz.fullName)
assert(sym == clazz || sym == module || sym == module.moduleClass)
@@ -24,6 +26,8 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
val loadingMirror = mirrorThatLoaded(sym)
val javaClass = loadingMirror.javaClass(clazz.javaClassName)
loadingMirror.unpickleClass(clazz, module, javaClass)
+ // NOTE: can't mark as thread-safe here, because unpickleClass might decide to delegate to FromJavaClassCompleter
+ // if (!isCompilerUniverse) markAllCompleted(clazz, module)
}
}
override def load(sym: Symbol) = complete(sym)
@@ -64,6 +68,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
sym setInfo new ClassInfoType(List(), new PackageScope(sym), sym)
// override def safeToString = pkgClass.toString
openPackageModule(sym)
+ markAllCompleted(sym)
}
}
diff --git a/src/reflect/scala/reflect/runtime/SymbolTable.scala b/src/reflect/scala/reflect/runtime/SymbolTable.scala
index ddbf3bd629..02155578f8 100644
--- a/src/reflect/scala/reflect/runtime/SymbolTable.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolTable.scala
@@ -28,19 +28,4 @@ private[scala] trait SymbolTable extends internal.SymbolTable with JavaMirrors w
* in order to prevent memory leaks: http://groups.google.com/group/scala-internals/browse_thread/thread/eabcf3d406dab8b2.
*/
override def isCompilerUniverse = false
-
- /** Unlike compiler universes, reflective universes can auto-initialize symbols on flag requests.
- *
- * scalac wasn't designed with such auto-initialization in mind, and quite often it makes assumptions
- * that flag requests won't cause initialization. Therefore enabling auto-init leads to cyclic errors.
- * We could probably fix those, but at the moment it's too risky.
- *
- * Reflective universes share codebase with scalac, but their surface is much smaller, which means less assumptions.
- * These assumptions are taken care of in this overriden `shouldTriggerCompleter` method.
- */
- override protected def shouldTriggerCompleter(symbol: Symbol, completer: Type, isFlagRelated: Boolean, mask: Long) =
- completer match {
- case _: TopClassCompleter | _: JavaClassCompleter => !isFlagRelated || (mask & TopLevelPickledFlags) != 0
- case _ => super.shouldTriggerCompleter(symbol, completer, isFlagRelated, mask)
- }
}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
index 1a232c8de1..f5e16c6640 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
@@ -4,6 +4,7 @@ package runtime
import scala.reflect.io.AbstractFile
import scala.collection.{ immutable, mutable }
+import scala.reflect.internal.Flags._
private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable =>
@@ -31,23 +32,105 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
trait SynchronizedSymbol extends Symbol {
- def gilSynchronizedIfNotInited[T](body: => T): T = {
- // TODO JZ desired, but prone to race conditions. We need the runtime reflection based
- // type completers to establish a memory barrier upon initialization. Maybe a volatile
- // write? We need to consult with the experts here. Until them, lock pessimistically.
- //
- // `run/reflection-sync-subtypes.scala` fails about 1/50 times otherwise.
- //
- // if (isFullyInitialized) body
- // else gilSynchronized { body }
+ /** (Things written in this comment only applies to runtime reflection. Compile-time reflection,
+ * especially across phases and runs, is somewhat more complicated, but we won't be touching it,
+ * because at the moment we only care about synchronizing runtime reflection).
+ *
+ * As it has been noted on multiple occasions, generally speaking, reflection artifacts aren't thread-safe.
+ * Reasons for that differ from artifact to artifact. In some cases it's quite bad (e.g. types use a number
+ * of non-concurrent compiler caches, so we need to serialize certain operations on types in order to make
+ * sure that things stay deterministic). However, in case of symbols there's hope, because it's only during
+ * initializaton that symbols are thread-unsafe. After everything's set up, symbols become immutable
+ * (sans a few deterministic caches that can be populated simultaneously by multiple threads) and therefore thread-safe.
+ *
+ * Note that by saying "symbols become immutable" I mean literally that. In a very common case of PackageClassSymbol's,
+ * even when a symbol finishes its initialization and becomes immutable, its info forever remains mutable.
+ * Therefore even if we no longer need to synchronize a PackageClassSymbol after it's initialized, we still have to take
+ * care of its ClassInfoType (or, more precisely, of the underlying Scope), but that's done elsewhere, and
+ * here we don't need to worry about that.
+ *
+ * Okay, so now we simply check `Symbol.isInitialized` and if it's true, then everything's fine? Haha, nope!
+ * The thing is that some completers call sym.setInfo when still in-flight and then proceed with initialization
+ * (e.g. see LazyPackageType). Consequently, setInfo sets _validTo to current period, which means that after
+ * a call to setInfo isInitialized will start returning true. Unfortunately, this doesn't mean that info becomes
+ * ready to be used, because subsequent initialization might change the info.
+ *
+ * Therefore we need to somehow distinguish between initialized and really initialized symbol states.
+ * Okay, let's do it on per-completer basis. We have seven kinds of completers to worry about:
+ * 1) LazyPackageType that initializes packages and their underlying package classes
+ * 2) TopClassCompleter that initializes top-level Scala-based class-module companion pairs of static definitions
+ * 3) LazyTypeRef and LazyTypeRefAndAlias set up by TopClassCompleter that initialize (transitive members) of top-level classes/modules
+ * 4) FromJavaClassCompleter that does the same for both top-level and non-toplevel Java-based classes/modules
+ * 5) Fully-initialized signatures of non-class/module Java-based reflection artifacts
+ * 6) Importing completer that transfers metadata from one universe to another
+ * 7) Signatures of special symbols such as roots and symbolsNotPresentInBytecode
+ *
+ * The mechanisms underlying completion are quite complex, and it'd be only natural to suppose that over time we're going to overlook something.
+ * Wrt isThreadsafe we could have two wrong situations: false positives (isThreadsafe = true, but the symbol isn't actually threadsafe)
+ * and false negatives (isThreadsafe = false, but the symbol is actually threadsafe). However, even though both are wrong, only the former
+ * is actively malicious. Indeed, false positives might lead to races, inconsistent state and crashes, while the latter would only cause
+ * `initialize` to be called and a gil to be taken on every potentially auto-initializable operation. Unpleasant yes, but still robust.
+ *
+ * What makes me hopeful is that:
+ * 1) By default (e.g. if some new completion mechanism gets introduced for a special flavor of symbols and we forget to call markCompleted)
+ * isThreadsafe is always in false negative state, which is unpleasant but safe.
+ * 2) Calls to `markCompleted` which are the only potential source of erroneous behavior are few and are relatively easy to place:
+ * just put them just before your completer's `complete` returns, and you should be fine.
+ *
+ * upd. Actually, there's another problem of not keeping initialization mask up-to-date. If we're not careful enough,
+ * then it might so happen that getting a certain flag that the compiler assumes to be definitively set will spuriously
+ * return isThreadsafe(purpose = FlagsOp(<flag>)) = false and that will lead to spurious auto-initialization,
+ * which will cause an SO or a cyclic reference or some other crash. I've done my best to go through all possible completers
+ * and call `markFlagsCompleted` where appropriate, but again over time something might be overlooked, so to guard against that
+ * I'm only considering TopLevelPickledFlags to be sources of potential initialization. This ensures that such system flags as
+ * isMethod, isModule or isPackage are never going to auto-initialize.
+ */
+ override def isThreadsafe(purpose: SymbolOps) = {
+ if (isCompilerUniverse) false
+ else if (_initialized) true
+ else purpose.isFlagRelated && (_initializationMask & purpose.mask & TopLevelPickledFlags) == 0
+ }
+
+ /** Communicates with completers declared in scala.reflect.runtime.SymbolLoaders
+ * about the status of initialization of the underlying symbol.
+ *
+ * Unfortunately, it's not as easy as just introducing the `markThreadsafe` method that would be called
+ * by the completers when they are really done (as opposed to `setInfo` that, as mentioned above, doesn't mean anything).
+ *
+ * Since we also want to auto-initialize symbols when certain methods are being called (`Symbol.hasFlag` for example),
+ * we need to track the identity of the initializer, so as to block until initialization is complete if the caller
+ * comes from a different thread, but to skip auto-initialization if we're the initializing thread.
+ *
+ * Just a volatile var is fine, because:
+ * 1) Status can only be changed in a single-threaded fashion (this is enforced by gilSynchronized
+ * that effecively guards `Symbol.initialize`), which means that there can't be update conflicts.
+ * 2) If someone reads a stale value of status, then the worst thing that might happen is that this someone
+ * is going to spuriously call `initialize`, which is either a gil-protected operation (if the symbol isn't inited yet)
+ * or a no-op (if the symbol is already inited), and that is fine in both cases.
+ *
+ * upd. It looks like we also need to keep track of a mask of initialized flags to make sure
+ * that normal symbol initialization routines don't trigger auto-init in Symbol.flags-related routines (e.g. Symbol.getFlag).
+ * Due to the same reasoning as above, a single volatile var is enough for to store the mask.
+ */
+ @volatile private[this] var _initialized = false
+ @volatile private[this] var _initializationMask = TopLevelPickledFlags
+ override def markFlagsCompleted(mask: Long): this.type = { _initializationMask = _initializationMask & ~mask; this }
+ override def markAllCompleted(): this.type = { _initializationMask = 0L; _initialized = true; this }
+
+ def gilSynchronizedIfNotThreadsafe[T](body: => T): T = {
+ // TODO: debug and fix the race that doesn't allow us uncomment this optimization
+ // if (isCompilerUniverse || isThreadsafe(purpose = AllOps)) body
+ // else gilSynchronized { body }
gilSynchronized { body }
}
- override def validTo = gilSynchronizedIfNotInited { super.validTo }
- override def info = gilSynchronizedIfNotInited { super.info }
- override def rawInfo: Type = gilSynchronizedIfNotInited { super.rawInfo }
+ override def validTo = gilSynchronizedIfNotThreadsafe { super.validTo }
+ override def info = gilSynchronizedIfNotThreadsafe { super.info }
+ override def rawInfo: Type = gilSynchronizedIfNotThreadsafe { super.rawInfo }
+ override def typeSignature: Type = gilSynchronizedIfNotThreadsafe { super.typeSignature }
+ override def typeSignatureIn(site: Type): Type = gilSynchronizedIfNotThreadsafe { super.typeSignatureIn(site) }
- override def typeParams: List[Symbol] = gilSynchronizedIfNotInited {
+ override def typeParams: List[Symbol] = gilSynchronizedIfNotThreadsafe {
if (isCompilerUniverse) super.typeParams
else {
if (isMonomorphicType) Nil
@@ -63,7 +146,7 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
}
}
}
- override def unsafeTypeParams: List[Symbol] = gilSynchronizedIfNotInited {
+ override def unsafeTypeParams: List[Symbol] = gilSynchronizedIfNotThreadsafe {
if (isCompilerUniverse) super.unsafeTypeParams
else {
if (isMonomorphicType) Nil
@@ -71,8 +154,6 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
}
}
- override def isStable: Boolean = gilSynchronized { super.isStable }
-
// ------ creators -------------------------------------------------------------------
override protected def createAbstractTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AbstractTypeSymbol =
@@ -126,7 +207,7 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
// 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 = gilSynchronizedIfNotInited { typeAsMemberOfLock.synchronized { super.typeAsMemberOf(pre) } }
+ override def typeAsMemberOf(pre: Type): Type = gilSynchronizedIfNotThreadsafe { typeAsMemberOfLock.synchronized { super.typeAsMemberOf(pre) } }
}
trait SynchronizedModuleSymbol extends ModuleSymbol with SynchronizedTermSymbol
@@ -135,7 +216,7 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
// unlike with typeConstructor, a lock is necessary here, because tpe calculation relies on
// temporarily assigning NoType to tpeCache to detect cyclic reference errors
private lazy val tpeLock = new Object
- override def tpe_* : Type = gilSynchronizedIfNotInited { tpeLock.synchronized { super.tpe_* } }
+ override def tpe_* : Type = gilSynchronizedIfNotThreadsafe { tpeLock.synchronized { super.tpe_* } }
}
trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
index 83d471f91e..9bcf85dd6f 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
@@ -50,13 +50,6 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
private lazy val _intersectionWitness = mkThreadLocalStorage(perRunCaches.newWeakMap[List[Type], sWeakRef[Type]]())
override def intersectionWitness = _intersectionWitness.get
- private lazy val _volatileRecursions = mkThreadLocalStorage(0)
- override def volatileRecursions = _volatileRecursions.get
- override def volatileRecursions_=(value: Int) = _volatileRecursions.set(value)
-
- private lazy val _pendingVolatiles = mkThreadLocalStorage(new mutable.HashSet[Symbol])
- override def pendingVolatiles = _pendingVolatiles.get
-
private lazy val _subsametypeRecursions = mkThreadLocalStorage(0)
override def subsametypeRecursions = _subsametypeRecursions.get
override def subsametypeRecursions_=(value: Int) = _subsametypeRecursions.set(value)