diff options
4 files changed, 67 insertions, 44 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index c2ad1fd426..af9c28232d 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -27,6 +27,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { import collection.mutable private val guardedCtorStats: mutable.Map[Symbol, List[Tree]] = new mutable.HashMap[Symbol, List[Tree]] + private val ctorParams: mutable.Map[Symbol, List[Symbol]] = new mutable.HashMap[Symbol, List[Symbol]] def transformClassTemplate(impl: Template): Template = { val clazz = impl.symbol.owner // the transformed class @@ -300,7 +301,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { case _ => false } - log("merging: " + originalStats.mkString("\n") + " : " + specializedStats.mkString("\n")) + log("merging: " + originalStats.mkString("\n") + "\nwith\n" + specializedStats.mkString("\n")) val res = for (s <- originalStats; val stat = s.duplicate) yield { log("merge: looking at " + stat) val stat1 = stat match { @@ -314,8 +315,13 @@ abstract class Constructors extends Transform with ast.TreeDSL { } if (stat1 eq stat) { + assert(ctorParams(genericClazz).length == constrParams.length) + // this is just to make private fields public + (new specializeTypes.ImplementationAdapter(ctorParams(genericClazz), constrParams, null, true))(stat1) + // statements coming from the original class need retyping in the current context if (settings.debug.value) log("retyping " + stat1) + val d = new specializeTypes.Duplicator d.retyped(localTyper.context1.asInstanceOf[d.Context], stat1, @@ -350,6 +356,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { if (usesSpecializedField && shouldGuard && postfix.nonEmpty) { // save them for duplication in the specialized subclass guardedCtorStats(clazz) = postfix + ctorParams(clazz) = constrParams val tree = If( diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 60634c467f..ede742bcf7 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -933,6 +933,52 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val global: SpecializeTypes.this.global.type = SpecializeTypes.this.global } with typechecker.Duplicators + /** A tree symbol substituter that substitutes on type skolems. + * If a type parameter is a skolem, it looks for the original + * symbol in the 'from' and maps it to the corresponding new + * symbol. The new symbol should probably be a type skolem as + * well (not enforced). + * + * All private members are made protected in order to be accessible from + * specialized classes. + */ + class ImplementationAdapter(from: List[Symbol], + to: List[Symbol], + targetClass: Symbol, + addressFields: Boolean) extends TreeSymSubstituter(from, to) { + override val symSubst = new SubstSymMap(from, to) { + override def matches(sym1: Symbol, sym2: Symbol) = + if (sym2.isTypeSkolem) sym2.deSkolemize eq sym1 + else sym1 eq sym2 + } + + private def isAccessible(sym: Symbol): Boolean = + (currentClass == sym.owner.enclClass) && (currentClass != targetClass) + + private def shouldMakePublic(sym: Symbol): Boolean = + sym.hasFlag(PRIVATE | PROTECTED) && (addressFields || !nme.isLocalName(sym.name)) + + /** All private members that are referenced are made protected, + * in order to be accessible from specialized subclasses. + */ + override def transform(tree: Tree): Tree = tree match { + case Select(qual, name) => + val sym = tree.symbol + if (sym.hasFlag(PRIVATE)) + if (settings.debug.value) + log("seeing private member %s, currentClass: %s, owner: %s, isAccessible: %b, isLocalName: %b" + .format(sym, currentClass, sym.owner.enclClass, isAccessible(sym), nme.isLocalName(sym.name))) + if (shouldMakePublic(sym) && !isAccessible(sym)) { + if (settings.debug.value) log("changing private flag of " + sym) + sym.makeNotPrivate(sym.owner) + } + super.transform(tree) + + case _ => + super.transform(tree) + } + } + def specializeCalls(unit: CompilationUnit) = new TypingTransformer(unit) { /** Map a specializable method to it's rhs, when not deferred. */ val body: mutable.Map[Symbol, Tree] = new mutable.HashMap @@ -1217,54 +1263,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val symSubstituter = new ImplementationAdapter( parameters(source).flatten ::: origtparams, vparamss1.flatten.map(_.symbol) ::: newtparams, - source.enclClass) + source.enclClass, + false) // don't make private fields public val tmp = symSubstituter(body(source).duplicate) tpt.tpe = tpt.tpe.substSym(oldtparams, newtparams) treeCopy.DefDef(tree, mods, name, tparams, vparamss1, tpt, tmp) } - /** A tree symbol substituter that substitutes on type skolems. - * If a type parameter is a skolem, it looks for the original - * symbol in the 'from' and maps it to the corresponding new - * symbol. The new symbol should probably be a type skolem as - * well (not enforced). - * - * All private members are made protected in order to be accessible from - * specialized classes. - */ - class ImplementationAdapter(from: List[Symbol], to: List[Symbol], targetClass: Symbol) extends TreeSymSubstituter(from, to) { - override val symSubst = new SubstSymMap(from, to) { - override def matches(sym1: Symbol, sym2: Symbol) = - if (sym2.isTypeSkolem) sym2.deSkolemize eq sym1 - else sym1 eq sym2 - } - - private def isAccessible(sym: Symbol): Boolean = - (currentClass == sym.owner.enclClass) && (currentClass != targetClass) - - /** All private members that are referenced are made protected, - * in order to be accessible from specialized subclasses. - */ - override def transform(tree: Tree): Tree = tree match { - case Select(qual, name) => - val sym = tree.symbol - if (sym.hasFlag(PRIVATE)) - if (settings.debug.value) log("seeing private member " + sym + " targetClass: " + currentClass + " owner: " + sym.owner.enclClass) - if (sym.hasFlag(PRIVATE | PROTECTED) && !nme.isLocalName(sym.name) && !isAccessible(sym)) { - if (settings.debug.value) log("changing private flag of " + sym) -// tree.symbol.resetFlag(PRIVATE).setFlag(PROTECTED) - sym.makeNotPrivate(sym.owner) -// tree.symbol.resetFlag(PRIVATE | PROTECTED) -// tree.symbol.privateWithin = NoSymbol - } - super.transform(tree) - - case _ => - super.transform(tree) - } - } - def warn(clazz: Symbol)(pos: Position, err: String) = if (!clazz.hasFlag(SPECIALIZED)) unit.warning(pos, err) diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index 78f43296b4..dbc3ffbe17 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -189,6 +189,7 @@ abstract class Duplicators extends Analyzer { if (tree.hasSymbol && tree.symbol != NoSymbol && !tree.symbol.isLabel // labels cannot be retyped by the type checker as LabelDef has no ValDef/return type trees && invalidSyms.isDefinedAt(tree.symbol)) { + if (settings.debug.value) log("removed symbol " + tree.symbol) tree.symbol = NoSymbol } @@ -240,7 +241,9 @@ abstract class Duplicators extends Analyzer { case Select(th @ This(_), sel) if (oldClassOwner ne null) && (th.symbol == oldClassOwner) => log("selection on this, no type ascription required") - super.typed(atPos(tree.pos)(Select(This(newClassOwner), sel)), mode, pt) + // we use the symbol name instead of the tree name because the symbol may have been + // name mangled, rendering the tree name obsolete + super.typed(atPos(tree.pos)(Select(This(newClassOwner), tree.symbol.name)), mode, pt) case This(_) if (oldClassOwner ne null) && (tree.symbol == oldClassOwner) => // val tree1 = Typed(This(newClassOwner), TypeTree(fixType(tree.tpe.widen))) diff --git a/test/files/pos/spec-constr.scala b/test/files/pos/spec-constr.scala new file mode 100644 index 0000000000..e908b65a41 --- /dev/null +++ b/test/files/pos/spec-constr.scala @@ -0,0 +1,7 @@ +class SparseArray2[@specialized(Int) T:ClassManifest](val maxSize: Int, initialLength:Int = 3) { + private var data = new Array[T](initialLength); + private var index = new Array[Int](initialLength); + + // comment out to compile correctly + data.length + 3; +} |