summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2015-07-13 10:13:23 +1000
committerJason Zaugg <jzaugg@gmail.com>2015-07-13 10:13:23 +1000
commitfc7cb9a91918cfdf7afe0600a87290ff71f88f12 (patch)
tree0f3e285550639d47ed897de660978eee9bfde6b0
parentb92c3aff1ab8c76c4816bd7b1a82a0f87d787837 (diff)
downloadscala-fc7cb9a91918cfdf7afe0600a87290ff71f88f12.tar.gz
scala-fc7cb9a91918cfdf7afe0600a87290ff71f88f12.tar.bz2
scala-fc7cb9a91918cfdf7afe0600a87290ff71f88f12.zip
SI-9392 Avoid crash in GenBCode for incoherent trees
A macro in shapeless was generating a tree of the form: ``` { class C#2 new C#2 }.setType(C#1) ``` This happened due to an error in the macro; it used untypecheck to try to fix the owner-chain consistency problem, but kept a reference to the previous version of the block-local class symbol `C` and used this in the resulting tree. This commit detects the particular situation we encountered, and avoids the crash by not creating the `NestedInfo` for the `BType` corresponding to `C#1`. The code comment discusses why I think this is safe, and suggests a refactoring that would mean we only ever try to construct `NestedInfo` when we are going to need them.
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala8
-rw-r--r--test/files/pos/t9392/client_2.scala4
-rw-r--r--test/files/pos/t9392/macro_1.scala16
3 files changed, 28 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
index 5f8f0e167c..85f07576ab 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
@@ -351,6 +351,14 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
val isTopLevel = innerClassSym.rawowner.isPackageClass
// impl classes are considered top-level, see comment in BTypes
if (isTopLevel || considerAsTopLevelImplementationArtifact(innerClassSym)) None
+ else if (innerClassSym.rawowner.isTerm)
+ // SI-9392 An errant macro might leave a reference to a local class symbol that no longer exists in the tree,
+ // this avoids an assertion error in that case. AFAICT, we don't actually need the `NestedInfo` for all BTypes,
+ // only for ones that describe classes defined in the trees that reach the backend, so this is safe enough.
+ //
+ // TODO Can we avoid creating `NestedInfo` for each type that is referred to, and instead only create if for
+ // symbols of ClassDefs?
+ None
else {
// See comment in BTypes, when is a class marked static in the InnerClass table.
val isStaticNestedClass = isOriginallyStaticOwner(innerClassSym.originalOwner)
diff --git a/test/files/pos/t9392/client_2.scala b/test/files/pos/t9392/client_2.scala
new file mode 100644
index 0000000000..6b706fea12
--- /dev/null
+++ b/test/files/pos/t9392/client_2.scala
@@ -0,0 +1,4 @@
+class Client {
+ Macro()
+}
+
diff --git a/test/files/pos/t9392/macro_1.scala b/test/files/pos/t9392/macro_1.scala
new file mode 100644
index 0000000000..3f67ac17b2
--- /dev/null
+++ b/test/files/pos/t9392/macro_1.scala
@@ -0,0 +1,16 @@
+import language.experimental.macros
+
+
+object Macro {
+
+ import reflect.macros.blackbox.Context
+ def impl(c: Context)(): c.Tree = {
+ import c.universe._
+ val tree = q"""class C; new C"""
+ val tree1 = c.typecheck(tree)
+ val tpe = tree1.tpe
+ val tree2 = c.typecheck(c.untypecheck(tree1))
+ q"""$tree2.asInstanceOf[$tpe]"""
+ }
+ def apply(): Any = macro impl
+}