diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala | 60 | ||||
-rw-r--r-- | test/files/jvm/protectedacc.check | 10 | ||||
-rw-r--r-- | test/files/jvm/protectedacc.scala | 51 |
3 files changed, 85 insertions, 36 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 1e7244e8d2..e41da55549 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -172,6 +172,13 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT val Select(qual, name) = tree val sym = tree.symbol val clazz = hostForAccessorOf(sym, currentOwner.enclClass) + + /** Return a list of list of types of all value parameter sections. */ + def allParamTypes(tpe: Type): List[List[Type]] = tpe match { + case MethodType(pts, res) => pts :: allParamTypes(res) + case _ => Nil + } + assert(clazz != NoSymbol, sym) if (settings.debug.value) log("Decided for host class: " + clazz) @@ -179,29 +186,19 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT var protAcc = clazz.info.decl(accName) val hasArgs = sym.tpe.paramTypes != Nil if (protAcc == NoSymbol) { - val resTpe = tree.tpe - val argTypes = - if (hasArgs) - MethodType( - sym.tpe.paramTypes map {t => -// Console.print("Transforming " + t + "(sym=" + t.symbol +") to ") -// Console.println("" + clazz.typeOfThis + ".memberType = " + clazz.typeOfThis.memberType(t.symbol)) - - if (!t.symbol.isAbstractType || t.symbol.isTypeParameter) - clazz.typeOfThis.memberType(t.symbol) - else - t - }, - resTpe.resultType /*sym.tpe.resultType*/) - else - resTpe.resultType /*sym.tpe.resultType*/ + val argTypes = tree.tpe // transform(sym.tpe) protAcc = clazz.newMethod(tree.pos, nme.protName(sym.originalName)) .setInfo(MethodType(List(clazz.typeOfThis),argTypes)) clazz.info.decls.enter(protAcc); - val code = DefDef(protAcc, vparamss => - vparamss.tail.foldRight(Select(gen.mkAttributedRef(vparamss.head.head), sym): Tree) ( - (vparams, fun) => Apply(fun, (vparams map { v => makeArg(v, vparamss.head.head) } )))) + val code = DefDef(protAcc, vparamss => { + val obj = vparamss.head.head + vparamss.tail.zip(allParamTypes(sym.tpe)).foldLeft(Select(Ident(obj), sym): Tree) ( + (fun, pvparams) => { + Apply(fun, (List.map2(pvparams._1, pvparams._2) { (v, origTpe) => makeArg(v, obj, origTpe) } )) + }) + }) + if (settings.debug.value) log(code) accDefBuf(clazz) += typers(clazz).typed(code) @@ -212,16 +209,27 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT if (hasArgs) typer.typedOperator(res) else typer.typed(res) } - private def makeArg(v: Symbol, obj: Symbol): Tree = { -// Console.println("" + v + ".tpe = " + v.tpe + " .symbol = " -// + v.tpe.symbol + " isAbstractType = " + v.tpe.symbol.isAbstractType); + /** Adapt the given argument in call to protected member. + * Adaptation means adding a cast to a path-dependent type, for instance + * + * def prot$m(obj: Outer)(x: Inner) = obj.m(x.asInstanceOf[obj.Inner]). + * + * such a cast might be necessary when m expects an Outer.this.Inner (the + * outer of 'obj' and 'x' have to be the same). This restriction can't be + * expressed in the type system (but is implicit when defining method m). + */ + private def makeArg(v: Symbol, obj: Symbol, expectedTpe: Type): Tree = { val res = Ident(v) + val sym = v.tpe.symbol - if (v.tpe.symbol.isAbstractType && !v.tpe.symbol.isTypeParameter) { + val isDependentType = expectedTpe match { + case TypeRef(ThisType(outerSym), _, _) if (obj.isSubClass(outerSym)) => true + case _ => false + } + if (isDependentType) { val preciseTpe = typeRef(singleType(NoPrefix, obj), v.tpe.symbol, List()) - Console.println("precise tpe: " + preciseTpe) - TypeApply(Select(res, definitions.Any_asInstanceOf), - List(TypeTree(preciseTpe))) + TypeApply(Select(res, definitions.Any_asInstanceOf), + List(TypeTree(preciseTpe))) } else res diff --git a/test/files/jvm/protectedacc.check b/test/files/jvm/protectedacc.check index ae0f39b997..2479af69c0 100644 --- a/test/files/jvm/protectedacc.check +++ b/test/files/jvm/protectedacc.check @@ -1,12 +1,12 @@ 10 meth1(1) = 2 -meth2(1)(1) = 2 -meth2(1)(1) = 2 +meth2(1)(1) = prefix: 0 +meth2(1)(1) = prefix: 0 meth3 = class [I -10++ = 11 +100 = 100 count before: 3 count after: 4 10 meth1(1) = 2 -meth2(1)(1) = 2 -10++ = 11 +meth2(1)(1) = 10 +100 = 100 diff --git a/test/files/jvm/protectedacc.scala b/test/files/jvm/protectedacc.scala index a6bc8984c4..0fda40babe 100644 --- a/test/files/jvm/protectedacc.scala +++ b/test/files/jvm/protectedacc.scala @@ -29,11 +29,30 @@ package p { protected val x = 10; protected def meth1(x: Int) = x + 1; - protected def meth2(x: Int)(y: Int) = x + y; + protected def meth2(x: Int)(y: String) = y + (x - 1); protected def meth3 = Array(1, 2) 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; () } + } + } } package b { @@ -47,12 +66,12 @@ package p { Console.println("meth1(1) = " + meth1(1)); // test accesses from closures for (val x <- 1 until 3) - Console.println("meth2(1)(1) = " + meth2(1)(1)); + Console.println("meth2(1)(1) = " + meth2(1)("prefix: ")); Console.println("meth3 = " + meth3.getClass); val inc = &meth2(1); - Console.println("10++ = " + inc(10)); + Console.println("100 = " + inc("10")); getA.x; } @@ -76,14 +95,36 @@ package p { def m = { Console.println(x); Console.println("meth1(1) = " + meth1(1)); - Console.println("meth2(1)(1) = " + meth2(1)(1)); + Console.println("meth2(1)(1) = " + meth2(1)("1")); val inc = &meth2(1); - Console.println("10++ = " + inc(10)); + 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 { + getB.tie(self2) + } + } + } } } |