From df2ebee249f94bbba273ce70a9a3331d07131230 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 13 Nov 2013 22:24:09 +0100 Subject: Fix crasher in icode due to symbol mismatches in lifted methods These stem from the handling of the internal/external view or method type parameters by `thisMethodType` in `Namers`. I've now preseversed the orginal ValDefs favoured the latter when constructing the new DefDef, and made construction of all liftables consistent in this regard. --- src/main/scala/scala/async/internal/Lifter.scala | 81 ++++++++++++---------- .../scala/async/run/toughtype/ToughType.scala | 50 +++++++++++++ 2 files changed, 94 insertions(+), 37 deletions(-) diff --git a/src/main/scala/scala/async/internal/Lifter.scala b/src/main/scala/scala/async/internal/Lifter.scala index f49dcbb..295eb3f 100644 --- a/src/main/scala/scala/async/internal/Lifter.scala +++ b/src/main/scala/scala/async/internal/Lifter.scala @@ -105,45 +105,52 @@ trait Lifter { } val lifted = liftableSyms.map(symToTree).toList.map { - case vd@ValDef(_, _, tpt, rhs) => - import reflect.internal.Flags._ - val sym = vd.symbol - sym.setFlag(MUTABLE | STABLE | PRIVATE | LOCAL) - sym.name = name.fresh(sym.name.toTermName) - sym.modifyInfo(_.deconst) - ValDef(vd.symbol, gen.mkZero(vd.symbol.info)).setPos(vd.pos) - case dd@DefDef(mods, name, tparams, vparamss, tpt, rhs) => - import reflect.internal.Flags._ - val sym = dd.symbol - sym.name = this.name.fresh(sym.name.toTermName) - sym.setFlag(PRIVATE | LOCAL) - DefDef(dd.symbol, rhs).setPos(dd.pos) - case cd@ClassDef(_, _, _, impl) => - import reflect.internal.Flags._ - val sym = cd.symbol - sym.name = newTypeName(name.fresh(sym.name.toString).toString) - companionship.companionOf(cd.symbol) match { - case NoSymbol => - case moduleSymbol => - moduleSymbol.name = sym.name.toTermName - moduleSymbol.moduleClass.name = moduleSymbol.name.toTypeName - } - ClassDef(cd.symbol, impl).setPos(cd.pos) - case md@ModuleDef(_, _, impl) => - import reflect.internal.Flags._ - val sym = md.symbol - companionship.companionOf(md.symbol) match { - case NoSymbol => + t => + val treeLifted = t match { + case vd@ValDef(_, _, tpt, rhs) => + import reflect.internal.Flags._ + val sym = vd.symbol + sym.setFlag(MUTABLE | STABLE | PRIVATE | LOCAL) sym.name = name.fresh(sym.name.toTermName) - sym.moduleClass.name = sym.name.toTypeName - case classSymbol => // will be renamed by `case ClassDef` above. + sym.modifyInfo(_.deconst) + val zeroRhs = atPos(t.pos)(gen.mkZero(vd.symbol.info)) + treeCopy.ValDef(vd, Modifiers(sym.flags), sym.name, TypeTree(sym.tpe).setPos(t.pos), zeroRhs) + case dd@DefDef(_, _, tparams, vparamss, tpt, rhs) => + import reflect.internal.Flags._ + val sym = dd.symbol + sym.name = this.name.fresh(sym.name.toTermName) + sym.setFlag(PRIVATE | LOCAL) + // Was `DefDef(sym, rhs)`, but this ran afoul of `ToughTypeSpec.nestedMethodWithInconsistencyTreeAndInfoParamSymbols` + // due to the handling of type parameter skolems in `thisMethodType` in `Namers` + treeCopy.DefDef(dd, Modifiers(sym.flags), sym.name, tparams, vparamss, tpt, rhs) + case cd@ClassDef(_, _, tparams, impl) => + import reflect.internal.Flags._ + val sym = cd.symbol + sym.name = newTypeName(name.fresh(sym.name.toString).toString) + companionship.companionOf(cd.symbol) match { + case NoSymbol => + case moduleSymbol => + moduleSymbol.name = sym.name.toTermName + moduleSymbol.moduleClass.name = moduleSymbol.name.toTypeName + } + treeCopy.ClassDef(cd, Modifiers(sym.flags), sym.name, tparams, impl) + case md@ModuleDef(_, _, impl) => + import reflect.internal.Flags._ + val sym = md.symbol + companionship.companionOf(md.symbol) match { + case NoSymbol => + sym.name = name.fresh(sym.name.toTermName) + sym.moduleClass.name = sym.name.toTypeName + case classSymbol => // will be renamed by `case ClassDef` above. + } + treeCopy.ModuleDef(md, Modifiers(sym.flags), sym.name, impl) + case td@TypeDef(_, _, tparams, rhs) => + import reflect.internal.Flags._ + val sym = td.symbol + sym.name = newTypeName(name.fresh(sym.name.toString).toString) + treeCopy.TypeDef(td, Modifiers(sym.flags), sym.name, tparams, rhs) } - ModuleDef(md.symbol, impl).setPos(md.pos) - case td@TypeDef(_, _, _, rhs) => - import reflect.internal.Flags._ - val sym = td.symbol - sym.name = newTypeName(name.fresh(sym.name.toString).toString) - TypeDef(td.symbol, rhs).setPos(td.pos) + atPos(t.pos)(treeLifted) } lifted } diff --git a/src/test/scala/scala/async/run/toughtype/ToughType.scala b/src/test/scala/scala/async/run/toughtype/ToughType.scala index b342a00..1551856 100644 --- a/src/test/scala/scala/async/run/toughtype/ToughType.scala +++ b/src/test/scala/scala/async/run/toughtype/ToughType.scala @@ -135,9 +135,59 @@ class ToughTypeSpec { } foo } + + // This test was failing when lifting `def r` with: + // symbol value m#10864 does not exist in r$1 + // + // We generated: + // + // private[this] def r$1#5727[A#5728 >: Nothing#157 <: Any#156](m#5731: Foo#2349[A#5728]): Unit#208 = Bippy#2352.this.bar#5532({ + // m#5730; + // () + // }); + // + // Notice the incorrect reference to `m`. + // + // We compensated in `Lifter` by copying `ValDef` parameter symbols directly across. + // + // Turns out the behaviour stems from `thisMethodType` in `Namers`, which treats type parameter skolem symbols. + @Test def nestedMethodWithInconsistencyTreeAndInfoParamSymbols() { + import language.{reflectiveCalls, postfixOps} + import scala.concurrent.{Future, ExecutionContext, future, Await} + import scala.concurrent.duration._ + import scala.async.Async.{async, await} + import scala.async.internal.AsyncId + + class Foo[A] + + object Bippy { + + import ExecutionContext.Implicits.global + + def bar(f: => Unit): Unit = f + + def quux: Future[String] = ??? + + def foo = async { + def r[A](m: Foo[A])(n: A) = { + bar { + locally(m) + locally(n) + identity[A] _ + } + } + + await(quux) + + r(new Foo[String])("") + } + } + Bippy + } } trait A + trait B trait L[A2, B2 <: A2] { -- cgit v1.2.3