Skip to content

Commit fc7cb9a

Browse files
committed
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.
1 parent b92c3af commit fc7cb9a

File tree

3 files changed

+28
-0
lines changed

3 files changed

+28
-0
lines changed

src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,14 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
351351
val isTopLevel = innerClassSym.rawowner.isPackageClass
352352
// impl classes are considered top-level, see comment in BTypes
353353
if (isTopLevel || considerAsTopLevelImplementationArtifact(innerClassSym)) None
354+
else if (innerClassSym.rawowner.isTerm)
355+
// SI-9392 An errant macro might leave a reference to a local class symbol that no longer exists in the tree,
356+
// this avoids an assertion error in that case. AFAICT, we don't actually need the `NestedInfo` for all BTypes,
357+
// only for ones that describe classes defined in the trees that reach the backend, so this is safe enough.
358+
//
359+
// TODO Can we avoid creating `NestedInfo` for each type that is referred to, and instead only create if for
360+
// symbols of ClassDefs?
361+
None
354362
else {
355363
// See comment in BTypes, when is a class marked static in the InnerClass table.
356364
val isStaticNestedClass = isOriginallyStaticOwner(innerClassSym.originalOwner)

test/files/pos/t9392/client_2.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class Client {
2+
Macro()
3+
}
4+

test/files/pos/t9392/macro_1.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import language.experimental.macros
2+
3+
4+
object Macro {
5+
6+
import reflect.macros.blackbox.Context
7+
def impl(c: Context)(): c.Tree = {
8+
import c.universe._
9+
val tree = q"""class C; new C"""
10+
val tree1 = c.typecheck(tree)
11+
val tpe = tree1.tpe
12+
val tree2 = c.typecheck(c.untypecheck(tree1))
13+
q"""$tree2.asInstanceOf[$tpe]"""
14+
}
15+
def apply(): Any = macro impl
16+
}

0 commit comments

Comments
 (0)