From 738c1723f9b9f5e5caa0302b9c7705f653926c33 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 31 Dec 2017 15:16:42 +0100 Subject: [PATCH 1/4] Fix protected setter generation --- .../src/dotty/tools/dotc/transform/PostTyper.scala | 2 +- .../dotty/tools/dotc/transform/SuperAccessors.scala | 2 +- tests/pos/i3638.scala | 12 ++++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i3638.scala diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 56d5a011ec4b..46fb723e2391 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -218,7 +218,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase super.transform(tree1) } case tree @ Assign(sel: Select, _) => - superAcc.transformAssign(super.transform(tree)) + super.transform(superAcc.transformAssign(tree)) case Inlined(call, bindings, expansion) => // Leave only a call trace consisting of // - a reference to the top-level class from which the call was inlined, diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index 7049079e34b9..2c13776d9b32 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -271,7 +271,7 @@ class SuperAccessors(thisPhase: DenotTransformer) { val accPos = tree.pos.focus val protectedAccessor = clazz.info.decl(accName).symbol orElse { val newAcc = ctx.newSymbol( - clazz, accName, Artifact, accType, coord = accPos).enteredAfter(thisPhase) + clazz, accName, Artifact | Method, accType, coord = accPos).enteredAfter(thisPhase) val code = DefDef(newAcc, vrefss => { val (receiver :: value :: Nil) :: Nil = vrefss Assign(receiver.select(field), value).withPos(accPos) diff --git a/tests/pos/i3638.scala b/tests/pos/i3638.scala new file mode 100644 index 000000000000..a1b895f52689 --- /dev/null +++ b/tests/pos/i3638.scala @@ -0,0 +1,12 @@ +package p { + package a { + class JavaInteraction(arr: Array[Char]) + extends java.io.CharArrayReader(arr) { + class Inner { + { + count = count + } + } + } + } +} From faa0a1b52b7e130adc00f33f1b31616e608ddb64 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 1 Jan 2018 12:27:04 +0100 Subject: [PATCH 2/4] Add test As @smarter has noticed, the original i3638 seems to be a distillation of this larger test. --- tests/run/protectedacc.check | 15 ++++ tests/run/protectedacc.scala | 159 +++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 tests/run/protectedacc.check create mode 100644 tests/run/protectedacc.scala diff --git a/tests/run/protectedacc.check b/tests/run/protectedacc.check new file mode 100644 index 000000000000..aaac0d613e18 --- /dev/null +++ b/tests/run/protectedacc.check @@ -0,0 +1,15 @@ +10 +meth1(1) = 2 +meth1(1.0) = 2.0 +meth2(1)(1) = prefix: 0 +meth2(1)(1) = prefix: 0 +meth3 = class [I +100 = 100 +id(1) = 1 +id('a') = a +count before: 3 +count after: 4 +10 +meth1(1) = 2 +meth2(1)(1) = 10 +100 = 100 diff --git a/tests/run/protectedacc.scala b/tests/run/protectedacc.scala new file mode 100644 index 000000000000..43d218fa89fd --- /dev/null +++ b/tests/run/protectedacc.scala @@ -0,0 +1,159 @@ +//############################################################################ +// Test Java interaction with scala inner classes +//############################################################################ + +import java.io.{BufferedReader, File, FileWriter, InputStreamReader} + +/** The entry point of this test. It has to come first, + * before the package declarations. The parser wouldn't want it + * any other way. + */ +object Test { + def main(args: Array[String]): Unit = { + val b = new p.b.B; + val c = new b.C; + c.m + + val ji = new p.b.JavaInteraction(Array('a', 'b', 'c')); + (new ji.Inner).m; + + (new p.b.OuterObj.Inner).m + } +} + +package p { + package a { + + class A { + protected val x = 10; + + protected def meth1(x: Int) = x + 1; + protected def meth1(x: Double) = x + 1 + protected def meth2(x: Int)(y: String) = y + (x - 1); + protected def meth3 = Array(1, 2) + + protected def f[a](x: a) = x + + def getA: this.type = this; + } + + /** Test type members */ + trait HighlighterXXX { + type Node; + protected def highlight(node : Node) : Unit; + } + + /** Test type parameters */ + abstract class PolyA[a] { + protected def m(x: a): Unit; + + class B { + + trait Node { + def s: String = ""; + } + protected def tie(x: Node): Unit = { x.s; () } + } + } + + /** bug 853, longer path members */ + class Global { + abstract class Tree; + } + + trait HasNSC { + trait GlobalExt extends Global; + val global : GlobalExt; + import global._; + protected def doTyped(tree : Tree): Tree = tree; + def mkTree : Tree; + doTyped(mkTree); + } + } + + package b { + import a._; + + /** Test interaction with Scala inherited methods and currying. */ + class B extends A { + class C { + def m = { + Console.println(x); + Console.println("meth1(1) = " + meth1(1)); + Console.println("meth1(1.0) = " + meth1(1.0)); + // test accesses from closures + for (x <- 1 until 3) + Console.println("meth2(1)(1) = " + meth2(1)("prefix: ")); + + Console.println("meth3 = " + meth3.getClass); + + val inc = meth2(1)_; + Console.println("100 = " + inc("10")); + + Console.println("id(1) = " + f(1)) + Console.println("id('a') = " + f("a")) + + getA.x; + } + } + } + + /** Test interaction with Java inherited protected fields. */ + class JavaInteraction(arr: Array[Char]) extends java.io.CharArrayReader(arr) { + class Inner { + def m = { + Console.println("count before: " + count); + count = count + 1; + Console.println("count after: " + count); + } + } + } + + /** Test interaction when outer is an object. */ + object OuterObj extends p.a.A { + class Inner { + def m = { + Console.println(x); + Console.println("meth1(1) = " + meth1(1)); + Console.println("meth2(1)(1) = " + meth2(1)("1")); + + val inc = meth2(1)_; + Console.println("100 = " + inc("10")); + + getA.x; + } + } + } + + trait ScalaAutoEditXXX extends HighlighterXXX { + trait NodeImpl { + def self : Node; + highlight(self); + } + } + + abstract class X[T] extends PolyA[T] { + + trait Inner extends B { + def self: T; + def self2: Node; + def getB: Inner; + + m(self) + + trait InnerInner { + val g = getB + g.tie(self2.asInstanceOf[g.Node]) + } + } + } + + trait ScalaTyperXXX extends HasNSC { + val global : GlobalExt; + import global._; + trait XXX { + def foo(tree : Tree) = doTyped(tree); + } + } + } +} From f64ce145968f123d6c1b845801584eebe7126c93 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 3 Jan 2018 11:39:42 +0100 Subject: [PATCH 3/4] Don't make superAccessors private The previous logic made a super accessor private if it is put in a class (on behalf of a nested trait). This caused compilation from Tasty to fail, since at the point of Tasty generation the RHS of the accessor has not yet been generated (it will be generated later in resolveSuper), and therefore Unpickler concluded that the method is private and deferred, which is illegal. Making it private is anyway pointless, since the super accessor is referred to from an inner trait (that's why it was generated in the first place!) and therefore will be made non-private later on. --- .../src/dotty/tools/dotc/transform/SuperAccessors.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index 2c13776d9b32..f20f8c6ef38f 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -80,10 +80,10 @@ class SuperAccessors(thisPhase: DenotTransformer) { val superAcc = clazz.info.decl(superName) .suchThat(_.signature == superInfo.signature).symbol .orElse { - ctx.debuglog(s"add super acc ${sym.showLocated} to $clazz") - val deferredOrPrivate = if (clazz is Trait) Deferred else Private + ctx.debugLog(s"add super acc ${sym.showLocated} to $clazz") + val maybeDeferred = if (clazz is Trait) Deferred else EmptyFlags val acc = ctx.newSymbol( - clazz, superName, Artifact | Method | deferredOrPrivate, + clazz, superName, Artifact | Method | maybeDeferred, superInfo, coord = accPos).enteredAfter(thisPhase) // Diagnostic for SI-7091 if (!accDefs.contains(clazz)) From a3c5f12417fd1af259240c264634dcb5aa4b7267 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 4 Jan 2018 12:07:19 +0100 Subject: [PATCH 4/4] Fix typo --- compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index f20f8c6ef38f..c13ce4a39303 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -80,7 +80,7 @@ class SuperAccessors(thisPhase: DenotTransformer) { val superAcc = clazz.info.decl(superName) .suchThat(_.signature == superInfo.signature).symbol .orElse { - ctx.debugLog(s"add super acc ${sym.showLocated} to $clazz") + ctx.debuglog(s"add super acc ${sym.showLocated} to $clazz") val maybeDeferred = if (clazz is Trait) Deferred else EmptyFlags val acc = ctx.newSymbol( clazz, superName, Artifact | Method | maybeDeferred,