diff options
author | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2016-07-27 16:19:53 +0200 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2016-07-27 16:19:53 +0200 |
commit | d7b1c0e018027b822266961beeeab3d87f02cbb0 (patch) | |
tree | bc76f54dbe15bc0bdd56033f982ccfbffeb96fe0 | |
parent | 2af7ea0c44b4d274503921911d80a5c7baab06ab (diff) | |
download | dotty-d7b1c0e018027b822266961beeeab3d87f02cbb0.tar.gz dotty-d7b1c0e018027b822266961beeeab3d87f02cbb0.tar.bz2 dotty-d7b1c0e018027b822266961beeeab3d87f02cbb0.zip |
Quick-fix eclosingMethod attribute generation for t3048.scala
It's a funny interaction between:
elim-by-name(and erasure specifically);
lift-static;
supercalls.
object E extends F2(new B {})
Here we have an anonymous class new B {} that looks like it is created
by erasure.
For some reason this class forgets the link to original anonymous class:
SymDenot(E$annon1).initial.phase == erasure. I guess this is a bug.
Additionally, the owner of E$annon1 is an anonymous method inside E,
that is inSuperCall and thus we have an anonymous nested class that
has enclosingClass be package. This class looks like a top-level
anonymous class breaking a lot of assumptions in shared backend
and taking multiple branches in unexpected ways.
I'm not sure that this is a proper fix. I assume there's a bigger bug
around, but I don't quite understand it right now and I need to work on
other stuff.
Making a quick fix to unblock @odersky.
-rw-r--r-- | src/dotty/tools/backend/jvm/DottyBackendInterface.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 13 |
2 files changed, 16 insertions, 1 deletions
diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index f42a8eee2..30934605b 100644 --- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -648,12 +648,14 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma originalOwner } def originalOwner: Symbol = { + // used to populate the EnclosingMethod attribute. + // it is very tricky in presence of classes(and annonymous classes) defined inside supper calls. try { if (sym.exists) { val original = toDenot(sym).initial val validity = original.validFor val shiftedContext = ctx.withPhase(validity.phaseId) - val r = toDenot(sym)(shiftedContext).maybeOwner.enclosingClass(shiftedContext) + val r = toDenot(sym)(shiftedContext).maybeOwner.lexicallyEnclosingClass(shiftedContext) r } else NoSymbol } catch { diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 16c77ac30..ebb061c6b 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -844,6 +844,19 @@ object SymDenotations { enclClass(symbol, false) } + /** A class that in sourlce code would be lexically enclosing */ + final def lexicallyEnclosingClass(implicit ctx: Context): Symbol = { + def enclClass(sym: Symbol): Symbol = { + if (!sym.exists) + NoSymbol + else if (sym.isClass) + sym + else + enclClass(sym.owner) + } + enclClass(symbol) + } + /** A symbol is effectively final if it cannot be overridden in a subclass */ final def isEffectivelyFinal(implicit ctx: Context): Boolean = is(PrivateOrFinal) || !owner.isClass || owner.is(ModuleOrFinal) || owner.isAnonymousClass |