From cb37548ef85d471951867b9f8a97cb9b9820fc66 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sat, 23 Nov 2013 09:41:07 +0100 Subject: Symbol substutition must consider ClassInfoType#parents An upcoming change to uncurry, in which I plan to make substitution of `lambda params -> apply method params` requires that I first to fix a problem in symbol substition. This situation can arise when the body of this definition: def owner1(a: A) = { class C extends M[a.B] } is transplanted into a new owner that has a different symbol for `a`. I speculated that value classes might also be prone to the fact that symbol substitution neglected `ClassInfoType#parents`. We can test change with Value Classes: Partial Functions that are dependent on value class param type used to fail with a spurious overriding error, now they work correctly. --- .../run/value-class-partial-func-depmet.scala | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 test/files/run/value-class-partial-func-depmet.scala (limited to 'test/files') diff --git a/test/files/run/value-class-partial-func-depmet.scala b/test/files/run/value-class-partial-func-depmet.scala new file mode 100644 index 0000000000..12ff64ed36 --- /dev/null +++ b/test/files/run/value-class-partial-func-depmet.scala @@ -0,0 +1,24 @@ +class C +class A { class C } + +object Test { + def main(args: Array[String]) { + val a = new A + + new VC("").foo(a) + } +} + +class VC(val a: Any) extends AnyVal { + def foo(a: A) = { + val pf: PartialFunction[a.C, Any] = { case x => x } + (pf: PartialFunction[Null, Any]).isDefinedAt(null) + } +} + +// 2.11.0-M6 +// test/files/run/value-class-partial-func-depmet.scala:14: error: overriding method applyOrElse in trait PartialFunction of type [A1 <: a.C, B1 >: Any](x: A1, default: A1 => B1)B1; +// method applyOrElse has incompatible type +// val pf: PartialFunction[a.C, Any] = { case x => x } +// ^ +// one error found -- cgit v1.2.3 From 736613ea8a2fb3eede9bc01346a743c70b44eeaa Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sat, 23 Nov 2013 09:45:19 +0100 Subject: Substitute new parameter symbols into lambda body Previously, new synthetic parameter symbols were created for the apply method parameters, but only used in its `MethodType`. The `ValDef` trees of the function, along with their symbols, were used directly as the parameter trees of the apply method. % cat sandbox/test.scala object Test { (x: Int) => { (y: Int) => ??? } } % scalac-hash v2.10.3 -Xprint:typer,uncurry -uniqid ../scala2/sandbox/test.scala | egrep 'syntax|\bx' [info] v2.10.3 => /Users/jason/usr/scala-v2.10.3-0-g88b5d19 [[syntax trees at end of typer]] // test.scala ((x#12152: Int#351) => x#12152)#12151 [[syntax trees at end of uncurry]] // test.scala final def apply#15952(x#12152: Int#351): Int#351 = x#12152 This approach dates back a long way: c64152bc3. @odersky tells me it was most likely due to insufficent substitution/cloning machinery at the time. % qbin/scalac -Xprint:typer,uncurry -uniqid ../scala2/sandbox/test.scala | egrep 'syntax|\bx' [[syntax trees at end of typer]] // test.scala ((x#13685: Int#1760) => x#13685)#13671 [[syntax trees at end of uncurry]] // test.scala final def apply#13959(x#13960: Int#1760): Int#1760 = x#13960 To make this work, I had to fix a problem in symbol substition; this was commited in the previous commit. In the enclosed test, at Uncurry, the symbol of the nested class `N` had a `ClassInfoType`, which listed as a parent `M[a.C]`. When we substituted the new method parameter symbol `a` for the eponymous function parameter symbol, this was not touched. --- src/compiler/scala/tools/nsc/transform/UnCurry.scala | 6 +++--- .../run/delambdafy-dependent-on-param-subst-2.scala | 20 ++++++++++++++++++++ .../run/delambdafy-dependent-on-param-subst.flags | 1 + .../run/delambdafy-dependent-on-param-subst.scala | 20 ++++++++++++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 test/files/run/delambdafy-dependent-on-param-subst-2.scala create mode 100644 test/files/run/delambdafy-dependent-on-param-subst.flags create mode 100644 test/files/run/delambdafy-dependent-on-param-subst.scala (limited to 'test/files') diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index d1d4759ea5..a851585442 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -232,11 +232,11 @@ abstract class UnCurry extends InfoTransform } methSym setInfoAndEnter MethodType(paramSyms, restpe) - fun.vparams foreach (_.symbol.owner = methSym) - fun.body changeOwner (fun.symbol -> methSym) + fun.body changeOwner (fun.symbol -> methSym) + fun.body substituteSymbols (fun.vparams.map(_.symbol), paramSyms) val body = typedFunPos(fun.body) - val methDef = DefDef(methSym, List(fun.vparams), body) + val methDef = DefDef(methSym, body) // Have to repack the type to avoid mismatches when existentials // appear in the result - see SI-4869. diff --git a/test/files/run/delambdafy-dependent-on-param-subst-2.scala b/test/files/run/delambdafy-dependent-on-param-subst-2.scala new file mode 100644 index 0000000000..7b6fc597e8 --- /dev/null +++ b/test/files/run/delambdafy-dependent-on-param-subst-2.scala @@ -0,0 +1,20 @@ +trait M[-X] { + def m(x: X): Boolean +} + +class C +class A { class C } + +object Test { + def main(args: Array[String]) { + val a = new A + + // class O extends M[a.C] { def m(x: a.C) = true } + // (new O: M[Null]).m(null) // Okay + + ((a: A) => { + class N extends M[a.C] { def m(x: a.C) = true } + new N: M[Null] + }).apply(a).m(null) // NPE, missing bridge + } +} diff --git a/test/files/run/delambdafy-dependent-on-param-subst.flags b/test/files/run/delambdafy-dependent-on-param-subst.flags new file mode 100644 index 0000000000..2b27e19830 --- /dev/null +++ b/test/files/run/delambdafy-dependent-on-param-subst.flags @@ -0,0 +1 @@ +-Ydelambdafy:method \ No newline at end of file diff --git a/test/files/run/delambdafy-dependent-on-param-subst.scala b/test/files/run/delambdafy-dependent-on-param-subst.scala new file mode 100644 index 0000000000..7b6fc597e8 --- /dev/null +++ b/test/files/run/delambdafy-dependent-on-param-subst.scala @@ -0,0 +1,20 @@ +trait M[-X] { + def m(x: X): Boolean +} + +class C +class A { class C } + +object Test { + def main(args: Array[String]) { + val a = new A + + // class O extends M[a.C] { def m(x: a.C) = true } + // (new O: M[Null]).m(null) // Okay + + ((a: A) => { + class N extends M[a.C] { def m(x: a.C) = true } + new N: M[Null] + }).apply(a).m(null) // NPE, missing bridge + } +} -- cgit v1.2.3