From bbc584f0ac3586ce4e4a92e58f74ad69a15f0ed5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 19 Jun 2015 15:35:38 +0200 Subject: Fix problem with explicit outer accessors Even if an explicit outer accessor was a method, it got a TermRef as type. --- src/dotty/tools/dotc/transform/ExplicitOuter.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 912bc9b7f..eb231bfe7 100644 --- a/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -136,7 +136,9 @@ object ExplicitOuter { /** A new outer accessor or param accessor */ private def newOuterSym(owner: ClassSymbol, cls: ClassSymbol, name: TermName, flags: FlagSet)(implicit ctx: Context) = { - ctx.newSymbol(owner, name, Synthetic | flags, cls.owner.enclosingClass.typeRef, coord = cls.coord) + val target = cls.owner.enclosingClass.typeRef + val info = if (flags.is(Method)) ExprType(target) else target + ctx.newSymbol(owner, name, Synthetic | flags, info, coord = cls.coord) } /** A new param accessor for the outer field in class `cls` */ @@ -302,7 +304,7 @@ object ExplicitOuter { val outerAccessorCtx = ctx.withPhaseNoLater(ctx.lambdaLiftPhase) // lambdalift mangles local class names, which means we cannot reliably find outer acessors anymore ctx.log(i"outer to $toCls of $tree: ${tree.tpe}, looking for ${outerAccName(treeCls.asClass)(outerAccessorCtx)} in $treeCls") if (treeCls == toCls) tree - else loop(tree select outerAccessor(treeCls.asClass)(outerAccessorCtx)) + else loop(tree.select(outerAccessor(treeCls.asClass)(outerAccessorCtx)).ensureApplied) } ctx.log(i"computing outerpath to $toCls from ${ctx.outersIterator.map(_.owner).toList}") loop(This(ctx.owner.enclosingClass.asClass)) -- cgit v1.2.3 From 25304a028e6d1426b14ead4a469c362b8536d893 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 19 Jun 2015 16:15:04 +0200 Subject: Add initializers for lambdalift proxy fields If an inner class has proxy fields, we missed so far the assignment sfrom the proxy parameters in the primary constructor of the class to the proxy fields. Test case tries several variations of this. --- src/dotty/tools/dotc/ast/tpd.scala | 9 +++++++-- src/dotty/tools/dotc/transform/LambdaLift.scala | 15 ++++++++++++--- tests/run/i659.scala | 24 +++++++++++++++++++----- 3 files changed, 38 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 51011f90b..a35e0e523 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -76,8 +76,13 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def Block(stats: List[Tree], expr: Tree)(implicit ctx: Context): Block = ta.assignType(untpd.Block(stats, expr), stats, expr) - def maybeBlock(stats: List[Tree], expr: Tree)(implicit ctx: Context): Tree = - if (stats.isEmpty) expr else Block(stats, expr) + /** Join `stats` in front of `expr` creating a new block if necessary */ + def seq(stats: List[Tree], expr: Tree)(implicit ctx: Context): Tree = + if (stats.isEmpty) expr + else expr match { + case Block(estats, eexpr) => cpy.Block(expr)(stats ::: estats, eexpr) + case _ => Block(stats, expr) + } def If(cond: Tree, thenp: Tree, elsep: Tree)(implicit ctx: Context): If = ta.assignType(untpd.If(cond, thenp, elsep), thenp, elsep) diff --git a/src/dotty/tools/dotc/transform/LambdaLift.scala b/src/dotty/tools/dotc/transform/LambdaLift.scala index bffc7458e..41d6f3c43 100644 --- a/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -384,14 +384,23 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform private def addFreeParams(tree: Tree, proxies: List[Symbol])(implicit ctx: Context, info: TransformerInfo): Tree = proxies match { case Nil => tree case proxies => + val sym = tree.symbol val ownProxies = - if (!tree.symbol.isConstructor) proxies - else proxies.map(_.copy(owner = tree.symbol, flags = Synthetic | Param)) + if (!sym.isConstructor) proxies + else proxies.map(_.copy(owner = sym, flags = Synthetic | Param)) val freeParamDefs = ownProxies.map(proxy => transformFollowingDeep(ValDef(proxy.asTerm).withPos(tree.pos)).asInstanceOf[ValDef]) + def proxyInit(field: Symbol, param: Symbol) = + transformFollowingDeep(ref(field).becomes(ref(param))) + def copyParams(rhs: Tree) = { + ctx.log(i"copy params ${proxies.map(_.showLocated)}%, %, own = ${ownProxies.map(_.showLocated)}%, %") + seq((proxies, ownProxies).zipped.map(proxyInit), rhs) + } tree match { case tree: DefDef => - cpy.DefDef(tree)(vparamss = tree.vparamss.map(freeParamDefs ++ _)) + cpy.DefDef(tree)( + vparamss = tree.vparamss.map(freeParamDefs ++ _), + rhs = if (sym.isPrimaryConstructor) copyParams(tree.rhs) else tree.rhs) case tree: Template => cpy.Template(tree)(body = freeParamDefs ++ tree.body) } diff --git a/tests/run/i659.scala b/tests/run/i659.scala index 5f10f15e8..d1229515d 100644 --- a/tests/run/i659.scala +++ b/tests/run/i659.scala @@ -1,12 +1,26 @@ class Foo(val a: Int) { - //def foo = { {case x => x + a}: PartialFunction[Int, Int]} + def foo = { {case x => x + a}: PartialFunction[Int, Int]} class Bar { def result(x: Int) = x + a } def bar = new Bar } +class VFoo(val a: Int) extends AnyVal { + def foo = { {case x => x + a}: PartialFunction[Int, Int]} +} + object Test extends dotty.runtime.LegacyApp { - //val x = new Foo(1).foo.apply(2) - val y = new Foo(1).bar.result(2) - assert(y == 3, y) - //assert(x == 3, x) + + def Foo(a: Int) = { + class Bar { def result(x: Int) = x + a } + new Bar().result(2) + } + + val x1 = new Foo(1).bar.result(2) + assert(x1 == 3, s"x1 = $x1") + val x2 = Foo(1) + assert(x2 == 3, s"x2 = $x2") + val x3 = new Foo(1).foo.apply(2) + assert(x3 == 3, s"x3 = $x3") + val x4 = new VFoo(1).foo.apply(2) + assert(x4 == 3, s"x4 = $x4") } -- cgit v1.2.3