From 2ba6774766ec695fef36e605472100922b56b91f Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 8 Aug 2012 12:46:06 +0200 Subject: SI-5756 correctly reifies local module classes Unlike module classes that are going to be pickled (which are reified as `.moduleClass), module classes of local modules need to be reified as symbol defs. Otherwise we get a stack overflow: 1) Local modules are deemed to be free terms, 2) All free symbols are reified together with their type signature (so that they can be a) inspected by anyone interested, b) compiled at runtime), 3) Reifying a type signature of a module involves reifying its module class, 4) Reifying a module class involves reifying a module and calling its module class, This stack overflow doesn't happen for locatable modules, because they don't need to have their type signatures reified (these signatures can later be loaded from pickles if it becomes necessary). --- test/files/pos/t5756.scala | 6 ++++++ test/files/pos/t6204-a.scala | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 test/files/pos/t5756.scala create mode 100644 test/files/pos/t6204-a.scala (limited to 'test/files/pos') diff --git a/test/files/pos/t5756.scala b/test/files/pos/t5756.scala new file mode 100644 index 0000000000..45960fa8bd --- /dev/null +++ b/test/files/pos/t5756.scala @@ -0,0 +1,6 @@ +import scala.reflect.runtime.universe._ + +object Test extends App { + def tagme[T: TypeTag](x: T) = typeTag[T] + val foo = tagme{object Bar; Bar} +} \ No newline at end of file diff --git a/test/files/pos/t6204-a.scala b/test/files/pos/t6204-a.scala new file mode 100644 index 0000000000..bd8d5c437e --- /dev/null +++ b/test/files/pos/t6204-a.scala @@ -0,0 +1,9 @@ +import scala.reflect.runtime.universe._ + +object Bish { + def m { + object Bash { + typeOf[Option[_]] + } + } +} \ No newline at end of file -- cgit v1.2.3 From 4ced74a5eece7ff27e24b6dcd5f607c130fb1342 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 8 Aug 2012 13:20:09 +0200 Subject: SI-6204 reifier no longer causes cyclic errors When reifying certain trees/types reifier might decide that it needs to introduce auxiliary symbols to represent non-locatable components of types For example, when reifying a refined type we need to reify the symbols that correspond to its members (aka RefinedType.decls). Since these symbols are not stored in pickles, we can't do the usual staticClass(scala.Int) stuff, and are forced to actually create corresponding symbols inside the reificode (by "create" I mean literally create, by using newXXXSymbol methods). It looks like a generally good idea to not only create those symbols naked, but to also export their type signatures and annotations. However this brings problems with type inference. Say, a type of a method A depends on a type tag. To get a type of a type tag, the compiler needs to expand the corresponding macro (when the macro is being expanded, symbol A is marked as LOCKED). While reification macro expands, it might want to reify certain symbol definitions (as explained above). If one of these definitions is a class that contains method A, we're in trouble, since reifying the corresponding ClassInfoType will eventually call A.info, which will produce a cyclic reference error, because A is LOCKED. An obvious solution is to check whether a reified symbol definition is locked. If the symbol is locked, then the reifier bails (e.g. by reifying NoType instead of the actual type signature of the symbol). Being obvious this solution is also incorrect as illustrated by SI-6204. Sure we can check whether a symbol itself is locked, but we cannot check whether or not we reify someone who refers to the locked symbol. As of such I'm telling the reifier to bail whenever it needs to reify a symbol definition for a symbol that is not yet complete. Therefore reification can no longer cause inference of method result types, which eliminates the underlying problem. This is a harsh measure, but taking into account that we have an RC planned within a week, stability trumps completeness. --- .../scala/reflect/reify/utils/SymbolTables.scala | 21 ++++++++++++--------- test/files/pos/t6204-b.scala | 10 ++++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 test/files/pos/t6204-b.scala (limited to 'test/files/pos') diff --git a/src/compiler/scala/reflect/reify/utils/SymbolTables.scala b/src/compiler/scala/reflect/reify/utils/SymbolTables.scala index a7ac299317..d9b445af90 100644 --- a/src/compiler/scala/reflect/reify/utils/SymbolTables.scala +++ b/src/compiler/scala/reflect/reify/utils/SymbolTables.scala @@ -174,15 +174,18 @@ trait SymbolTables { if (sym.annotations.isEmpty) EmptyTree else Apply(Select(currtab.symRef(sym), nme.setAnnotations), List(reifier.reify(sym.annotations))) } else { - import scala.reflect.internal.Flags._ - if (sym hasFlag LOCKED) { - // [Eugene] better to have a symbol without a type signature, than to crash with a CyclicReference - EmptyTree - } else { - val rset = reifier.mirrorBuildCall(nme.setTypeSignature, currtab.symRef(sym), reifier.reify(sym.info)) - if (sym.annotations.isEmpty) rset - else reifier.mirrorBuildCall(nme.setAnnotations, rset, reifier.mkList(sym.annotations map reifier.reifyAnnotationInfo)) - } + // SI-6204 don't reify signatures for incomplete symbols, because this might lead to cyclic reference errors + val signature = + if (sym.hasCompleteInfo) { + if (sym.isCapturedVariable) capturedVariableType(sym) + else sym.info + } else NoType + val rset = reifier.mirrorBuildCall(nme.setTypeSignature, currtab.symRef(sym), reifier.reify(signature)) + // `Symbol.annotations` doesn't initialize the symbol, so we don't need to do anything special here + // also since we call `sym.info` a few lines above, by now the symbol will be initialized (if possible) + // so the annotations will be filled in and will be waiting to be reified (unless symbol initialization is prohibited as described above) + if (sym.annotations.isEmpty) rset + else reifier.mirrorBuildCall(nme.setAnnotations, rset, reifier.mkList(sym.annotations map reifier.reifyAnnotationInfo)) } } diff --git a/test/files/pos/t6204-b.scala b/test/files/pos/t6204-b.scala new file mode 100644 index 0000000000..86094d1a19 --- /dev/null +++ b/test/files/pos/t6204-b.scala @@ -0,0 +1,10 @@ +import scala.reflect.runtime.universe._ + +object Bosh { + def Besh { + new { + val t = typeOf[Option[_]] + val x = t + } + } +} \ No newline at end of file -- cgit v1.2.3