diff options
author | Paul Phillips <paulp@improving.org> | 2013-04-09 02:04:46 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2013-04-09 02:04:46 -0700 |
commit | 30e0fd0b8a8f7357df9d9fd5cbc73910f6548638 (patch) | |
tree | a49d49bd4ebfdd8e79843b6b259a31bc0867598d | |
parent | 967087811f9215d72651fc62e0977291efa2ab43 (diff) | |
parent | 7ee950fc3002632065e6f9e9b29e4c9be1138b88 (diff) | |
download | scala-30e0fd0b8a8f7357df9d9fd5cbc73910f6548638.tar.gz scala-30e0fd0b8a8f7357df9d9fd5cbc73910f6548638.tar.bz2 scala-30e0fd0b8a8f7357df9d9fd5cbc73910f6548638.zip |
Merge pull request #2375 from paulp/merge-2.10.x
Merge 2.10.x into master.
19 files changed, 292 insertions, 141 deletions
@@ -7,6 +7,14 @@ SuperSabbus for Scala core, builds the scala library and compiler. It can also package it as a simple distribution, tests it for stable bootstrapping and against the Scala test suite. </description> +<!-- HINTS + + - for faster builds, have a build.properties in the same directory as build.xml that says: + locker.skip=1 + starr.use.released=1 + +--> + <!-- USAGE FROM JENKINS SCRIPTS IS (CURRENTLY) AS FOLLOWS: ant $antArgs $scalacArgs $targets @@ -18,14 +26,12 @@ scalacArgs examples: "-Dscalac.args=\"-Yrangepos\" -Dpartest.scalac_opts=\"-Yrangepos\"" targets exercised: - build-opt nightly test.suite test.continuations.suite test.scaladoc locker.done + locker.done build-opt nightly test.suite test.continuations.suite test.scaladoc --> <!-- To use Zinc with the ant build: - install zinc and symlink the installed zinc script to ${basedir}/tools/zinc (${basedir} is where build.xml and the rest of your checkout resides) - make sure to set ZINC_OPTS to match ANT_OPTS! - - invoke ant as `ant -Dstarr.version="2.10.1" -Dlocker.skip=1` - (zinc needs compiler jars) --> <!-- @@ -106,9 +112,13 @@ TODO: <!-- Loads custom properties definitions --> <property file="${basedir}/build.properties"/> + <!-- Generating version number --> <property file="${basedir}/build.number"/> + <!-- read starr.version --> + <property file="${basedir}/starr.number"/> + <!-- Sets location of pre-compiled libraries --> <property name="library.starr.jar" value="${lib.dir}/scala-library.jar"/> <property name="reflect.starr.jar" value="${lib.dir}/scala-reflect.jar"/> @@ -219,15 +229,23 @@ TODO: <!-- BND support --> <typedef resource="aQute/bnd/ant/taskdef.properties" classpathref="extra.tasks.classpath" /> - <!-- Download STARR via maven if `starr.version` is specified. + <!-- Download STARR via maven if `starr.use.released` is set, + and `starr.version` is specified (see the starr.number properties file). Want to slow down STARR changes, using only released versions. --> - <if><isset property="starr.version"/><then> + <if><isset property="starr.use.released"/><then> + <echo message="Using Scala ${starr.version} for STARR."/> <artifact:dependencies pathId="starr.core.path"> <dependency groupId="org.scala-lang" artifactId="scala-library" version="${starr.version}"/> <dependency groupId="org.scala-lang" artifactId="scala-reflect" version="${starr.version}"/> <dependency groupId="org.scala-lang" artifactId="scala-compiler" version="${starr.version}"/> - </artifact:dependencies> - </then></if> + </artifact:dependencies></then> + <else> + <path id="starr.core.path"> + <pathelement location="${library.starr.jar}"/> + <pathelement location="${reflect.starr.jar}"/> + <pathelement location="${compiler.starr.jar}"/> + </path></else> + </if> <property name="maven-deps-done" value="yep!"/> </then></if> @@ -262,6 +280,10 @@ TODO: <property name="maven.version.suffix" value="${version.suffix}"/> <property name="osgi.version.suffix" value="${version.suffix}"/></else></if> + <!-- if a maven version suffix was set (or inferred), assume we're building a release --> + <if><isset property="maven.version.suffix"/><then> + <property name="build.release" value="1"/></then></if> + <!-- not building a release and no version.suffix specified --> <property name="maven.version.suffix" value="-SNAPSHOT"/> @@ -421,23 +443,10 @@ TODO: <path refid="aux.libs"/> </path> - <!-- Download STARR via maven if `starr.version` is specified. - Want to slow down STARR changes, using only released versions. --> - <if><isset property="starr.version"/><then> - <echo message="Using Scala ${starr.version} for STARR."/> - <!-- <echo message="STARR classpath: ${ant.refid:starr.compiler.path}"/> --> - </then><else> - <path id="starr.core.path"> - <pathelement location="${library.starr.jar}"/> - <pathelement location="${reflect.starr.jar}"/> - <pathelement location="${compiler.starr.jar}"/> - </path> - </else></if> - - <!-- Skip locker with -Dlocker.skip=YESSIR. Uses STARR instead. --> + <!-- To skip locker, use -Dlocker.skip=1 --> <if><isset property="locker.skip"/><then> - <echo message="Skipping locker! Using STARR instead."/> - <path id="locker.compiler.path"><path refid="starr.compiler.path"/></path> + <echo message="Using STARR to build the quick stage (skipping locker)."/> + <path id="locker.compiler.path" refid="starr.compiler.path"/> <property name="locker.locked" value="locker skipped"/></then> <else> <path id="locker.compiler.path"><path refid="locker.compiler.build.path"/></path></else></if> @@ -1170,11 +1179,11 @@ TODO: </staged-uptodate> </target> - <target name="quick.bin" depends="init"> + <target name="quick.bin" depends="quick.lib, quick.reflect, quick.comp, quick.repl, quick.scalacheck, quick.scalap, quick.interactive, quick.swing, quick.plugins, quick.partest, quick.scaladoc"> <staged-bin stage="quick" classpathref="quick.bin.tool.path"/> </target> - <target name="quick.done" depends="quick.lib, quick.reflect, quick.comp, quick.repl, quick.scalacheck, quick.scalap, quick.interactive, quick.swing, quick.plugins, quick.partest, quick.scaladoc, quick.bin"/> + <target name="quick.done" depends="quick.bin"/> <target name="quick-opt" description="Optimized version of quick.done."> <optimized name="quick.done"/></target> diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 22482bf1b6..250feb69bf 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -104,8 +104,15 @@ abstract class SymbolLoaders { val clazz = enterClass(root, name, completer) val module = enterModule(root, name, completer) if (!clazz.isAnonymousClass) { - assert(clazz.companionModule == module, module) - assert(module.companionClass == clazz, clazz) + // Diagnostic for SI-7147 + def msg: String = { + def symLocation(sym: Symbol) = if (sym == null) "null" else s"${clazz.fullLocationString} (from ${clazz.associatedFile})" + sm"""Inconsistent class/module symbol pair for `$name` loaded from ${symLocation(root)}. + |clazz = ${symLocation(clazz)}; clazz.companionModule = ${clazz.companionModule} + |module = ${symLocation(module)}; module.companionClass = ${module.companionClass}""" + } + assert(clazz.companionModule == module, msg) + assert(module.companionClass == clazz, msg) } } diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index ba19eb1035..8e008edde2 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -79,7 +79,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ /** For a given class and concrete type arguments, give its specialized class */ - val specializedClass: mutable.Map[(Symbol, TypeEnv), Symbol] = new mutable.LinkedHashMap + val specializedClass = perRunCaches.newMap[(Symbol, TypeEnv), Symbol] /** Map a method symbol to a list of its specialized overloads in the same class. */ private val overloads = perRunCaches.newMap[Symbol, List[Overload]]() withDefaultValue Nil @@ -1752,21 +1752,17 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Create specialized class definitions */ def implSpecClasses(trees: List[Tree]): List[Tree] = { - val buf = new mutable.ListBuffer[Tree] - for (tree <- trees) - tree match { - case ClassDef(_, _, _, impl) => - tree.symbol.info // force specialization - for (((sym1, env), specCls) <- specializedClass if sym1 == tree.symbol) { - val parents = specCls.info.parents.map(TypeTree) - buf += - ClassDef(specCls, atPos(impl.pos)(Template(parents, emptyValDef, List())) - .setSymbol(specCls.newLocalDummy(sym1.pos))) setPos tree.pos - debuglog("created synthetic class: " + specCls + " of " + sym1 + " in " + pp(env)) - } - case _ => - } - buf.toList + trees flatMap { + case tree @ ClassDef(_, _, _, impl) => + tree.symbol.info // force specialization + for (((sym1, env), specCls) <- specializedClass if sym1 == tree.symbol) yield { + debuglog("created synthetic class: " + specCls + " of " + sym1 + " in " + pp(env)) + val parents = specCls.info.parents.map(TypeTree) + ClassDef(specCls, atPos(impl.pos)(Template(parents, emptyValDef, List())) + .setSymbol(specCls.newLocalDummy(sym1.pos))) setPos tree.pos + } + case _ => Nil + } sortBy (_.name.decoded) } } diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index 92ed7fc555..313f968e93 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -217,7 +217,10 @@ abstract class TailCalls extends Transform { debuglog("Rewriting tail recursive call: " + fun.pos.lineContent.trim) accessed += ctx.label - typedPos(fun.pos)(Apply(Ident(ctx.label), noTailTransform(recv) :: transformArgs)) + typedPos(fun.pos) { + val args = mapWithIndex(transformArgs)((arg, i) => mkAttributedCastHack(arg, ctx.label.info.params(i + 1).tpe)) + Apply(Ident(ctx.label), noTailTransform(recv) :: args) + } } if (!ctx.isEligible) fail("it is neither private nor final so can be overridden") @@ -276,7 +279,7 @@ abstract class TailCalls extends Transform { typedPos(tree.pos)(Block( List(ValDef(newThis, This(currentClass))), - LabelDef(newCtx.label, newThis :: vpSyms, newRHS) + LabelDef(newCtx.label, newThis :: vpSyms, mkAttributedCastHack(newRHS, newCtx.label.tpe.resultType)) )) } else { @@ -373,6 +376,13 @@ abstract class TailCalls extends Transform { super.transform(tree) } } + + // Workaround for SI-6900. Uncurry installs an InfoTransformer and a tree Transformer. + // These leave us with conflicting view on method signatures; the parameter symbols in + // the MethodType can be clones of the ones originally found on the parameter ValDef, and + // consequently appearing in the typechecked RHS of the method. + private def mkAttributedCastHack(tree: Tree, tpe: Type) = + gen.mkAttributedCast(tree, tpe) } // collect the LabelDefs (generated by the pattern matcher) in a DefDef that are in tail position diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 8c1d0a76d0..2f5cb23abb 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -632,7 +632,8 @@ abstract class UnCurry extends InfoTransform * * This transformation erases the dependent method types by: * - Widening the formal parameter type to existentially abstract - * over the prior parameters (using `packSymbols`) + * over the prior parameters (using `packSymbols`). This transformation + * is performed in the the `InfoTransform`er [[scala.reflect.internal.transform.UnCurry]]. * - Inserting casts in the method body to cast to the original, * precise type. * @@ -660,15 +661,14 @@ abstract class UnCurry extends InfoTransform */ def erase(dd: DefDef): (List[List[ValDef]], Tree) = { import dd.{ vparamss, rhs } - val vparamSyms = vparamss flatMap (_ map (_.symbol)) - val paramTransforms: List[ParamTransform] = - vparamss.flatten.map { p => - val declaredType = p.symbol.info - // existentially abstract over value parameters - val packedType = typer.packSymbols(vparamSyms, declaredType) - if (packedType =:= declaredType) Identity(p) + map2(vparamss.flatten, dd.symbol.info.paramss.flatten) { (p, infoParam) => + val packedType = infoParam.info + if (packedType =:= p.symbol.info) Identity(p) else { + // The Uncurry info transformer existentially abstracted over value parameters + // from the previous parameter lists. + // Change the type of the param symbol p.symbol updateInfo packedType @@ -680,8 +680,8 @@ abstract class UnCurry extends InfoTransform // the method body to refer to this, rather than the parameter. val tempVal: ValDef = { val tempValName = unit freshTermName (p.name + "$") - val newSym = dd.symbol.newTermSymbol(tempValName, p.pos, SYNTHETIC).setInfo(declaredType) - atPos(p.pos)(ValDef(newSym, gen.mkAttributedCast(Ident(p.symbol), declaredType))) + val newSym = dd.symbol.newTermSymbol(tempValName, p.pos, SYNTHETIC).setInfo(p.symbol.info) + atPos(p.pos)(ValDef(newSym, gen.mkAttributedCast(Ident(p.symbol), p.symbol.info))) } Packed(newParam, tempVal) } @@ -699,13 +699,6 @@ abstract class UnCurry extends InfoTransform Block(tempVals, rhsSubstituted) } - // update the type of the method after uncurry. - dd.symbol updateInfo { - val GenPolyType(tparams, tp) = dd.symbol.info - logResult(s"erased dependent param types for ${dd.symbol.info}") { - GenPolyType(tparams, MethodType(allParams map (_.symbol), tp.finalResultType)) - } - } (allParams :: Nil, rhs1) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index b4270ea322..e22dc73b53 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -256,9 +256,16 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } } - // direct calls to aliases of param accessors to the superclass in order to avoid + + def isAccessibleFromSuper(sym: Symbol) = { + val pre = SuperType(sym.owner.tpe, qual.tpe) + localTyper.context.isAccessible(sym, pre, superAccess = true) + } + + // Direct calls to aliases of param accessors to the superclass in order to avoid // duplicating fields. - if (sym.isParamAccessor && sym.alias != NoSymbol) { + // ... but, only if accessible (SI-6793) + if (sym.isParamAccessor && sym.alias != NoSymbol && isAccessibleFromSuper(sym.alias)) { val result = (localTyper.typedPos(tree.pos) { Select(Super(qual, tpnme.EMPTY) setPos qual.pos, sym.alias) }).asInstanceOf[Select] diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 0be7192471..692c24fd20 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3678,77 +3678,9 @@ trait Typers extends Adaptations with Tags { }) } - def isRawParameter(sym: Symbol) = // is it a type parameter leaked by a raw type? - sym.isTypeParameter && sym.owner.isJavaDefined - - /** If we map a set of hidden symbols to their existential bounds, we - * have a problem: the bounds may themselves contain references to the - * hidden symbols. So this recursively calls existentialBound until - * the typeSymbol is not amongst the symbols being hidden. - */ - def existentialBoundsExcludingHidden(hidden: List[Symbol]): Map[Symbol, Type] = { - def safeBound(t: Type): Type = - if (hidden contains t.typeSymbol) safeBound(t.typeSymbol.existentialBound.bounds.hi) else t - - def hiBound(s: Symbol): Type = safeBound(s.existentialBound.bounds.hi) match { - case tp @ RefinedType(parents, decls) => - val parents1 = parents mapConserve safeBound - if (parents eq parents1) tp - else copyRefinedType(tp, parents1, decls) - case tp => tp - } - - // Hanging onto lower bound in case anything interesting - // happens with it. - mapFrom(hidden)(s => s.existentialBound match { - case TypeBounds(lo, hi) => TypeBounds(lo, hiBound(s)) - case _ => hiBound(s) - }) - } - - /** Given a set `rawSyms` of term- and type-symbols, and a type - * `tp`, produce a set of fresh type parameters and a type so that - * it can be abstracted to an existential type. Every type symbol - * `T` in `rawSyms` is mapped to a clone. Every term symbol `x` of - * type `T` in `rawSyms` is given an associated type symbol of the - * following form: - * - * type x.type <: T with Singleton - * - * The name of the type parameter is `x.type`, to produce nice - * diagnostics. The Singleton parent ensures that the type - * parameter is still seen as a stable type. Type symbols in - * rawSyms are fully replaced by the new symbols. Term symbols are - * also replaced, except for term symbols of an Ident tree, where - * only the type of the Ident is changed. - */ - protected def existentialTransform[T](rawSyms: List[Symbol], tp: Type)(creator: (List[Symbol], Type) => T): T = { - val allBounds = existentialBoundsExcludingHidden(rawSyms) - val typeParams: List[Symbol] = rawSyms map { sym => - val name = sym.name match { - case x: TypeName => x - case x => tpnme.singletonName(x) - } - val bound = allBounds(sym) - val sowner = if (isRawParameter(sym)) context.owner else sym.owner - val quantified = sowner.newExistential(name, sym.pos) - - quantified setInfo bound.cloneInfo(quantified) - } - // Higher-kinded existentials are not yet supported, but this is - // tpeHK for when they are: "if a type constructor is expected/allowed, - // tpeHK must be called instead of tpe." - val typeParamTypes = typeParams map (_.tpeHK) - def doSubst(info: Type) = info.subst(rawSyms, typeParamTypes) - - creator(typeParams map (_ modifyInfo doSubst), doSubst(tp)) - } - /** Compute an existential type from raw hidden symbols `syms` and type `tp` */ - def packSymbols(hidden: List[Symbol], tp: Type): Type = - if (hidden.isEmpty) tp - else existentialTransform(hidden, tp)(existentialAbstraction) + def packSymbols(hidden: List[Symbol], tp: Type): Type = global.packSymbols(hidden, tp, Some(context0.owner)) def isReferencedFrom(ctx: Context, sym: Symbol): Boolean = ctx.owner.isTerm && diff --git a/src/compiler/scala/tools/nsc/util/TreeSet.scala b/src/compiler/scala/tools/nsc/util/TreeSet.scala index 3cdbcc5110..d2e9238e8f 100644 --- a/src/compiler/scala/tools/nsc/util/TreeSet.scala +++ b/src/compiler/scala/tools/nsc/util/TreeSet.scala @@ -40,12 +40,22 @@ class TreeSet[T >: Null <: AnyRef](less: (T, T) => Boolean) extends Set[T] { tree = add(tree) } - def iterator = { - def elems(t: Tree): Iterator[T] = { - if (t eq null) Iterator.empty - else elems(t.l) ++ (Iterator single t.elem) ++ elems(t.r) + def iterator = toList.iterator + + override def foreach[U](f: T => U) { + def loop(t: Tree) { + if (t ne null) { + loop(t.l) + f(t.elem) + loop(t.r) + } } - elems(tree) + loop(tree) + } + override def toList = { + val xs = scala.collection.mutable.ListBuffer[T]() + foreach(xs += _) + xs.toList } override def toString(): String = { diff --git a/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala b/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala index 281a32caf6..34bd400186 100644 --- a/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala +++ b/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala @@ -31,4 +31,81 @@ trait ExistentialsAndSkolems { } (new Deskolemizer).typeSkolems } + + def isRawParameter(sym: Symbol) = // is it a type parameter leaked by a raw type? + sym.isTypeParameter && sym.owner.isJavaDefined + + /** If we map a set of hidden symbols to their existential bounds, we + * have a problem: the bounds may themselves contain references to the + * hidden symbols. So this recursively calls existentialBound until + * the typeSymbol is not amongst the symbols being hidden. + */ + private def existentialBoundsExcludingHidden(hidden: List[Symbol]): Map[Symbol, Type] = { + def safeBound(t: Type): Type = + if (hidden contains t.typeSymbol) safeBound(t.typeSymbol.existentialBound.bounds.hi) else t + + def hiBound(s: Symbol): Type = safeBound(s.existentialBound.bounds.hi) match { + case tp @ RefinedType(parents, decls) => + val parents1 = parents mapConserve safeBound + if (parents eq parents1) tp + else copyRefinedType(tp, parents1, decls) + case tp => tp + } + + // Hanging onto lower bound in case anything interesting + // happens with it. + mapFrom(hidden)(s => s.existentialBound match { + case TypeBounds(lo, hi) => TypeBounds(lo, hiBound(s)) + case _ => hiBound(s) + }) + } + + /** Given a set `rawSyms` of term- and type-symbols, and a type + * `tp`, produce a set of fresh type parameters and a type so that + * it can be abstracted to an existential type. Every type symbol + * `T` in `rawSyms` is mapped to a clone. Every term symbol `x` of + * type `T` in `rawSyms` is given an associated type symbol of the + * following form: + * + * type x.type <: T with Singleton + * + * The name of the type parameter is `x.type`, to produce nice + * diagnostics. The Singleton parent ensures that the type + * parameter is still seen as a stable type. Type symbols in + * rawSyms are fully replaced by the new symbols. Term symbols are + * also replaced, except for term symbols of an Ident tree, where + * only the type of the Ident is changed. + */ + final def existentialTransform[T](rawSyms: List[Symbol], tp: Type, rawOwner: Option[Symbol] = None)(creator: (List[Symbol], Type) => T): T = { + val allBounds = existentialBoundsExcludingHidden(rawSyms) + val typeParams: List[Symbol] = rawSyms map { sym => + val name = sym.name match { + case x: TypeName => x + case x => tpnme.singletonName(x) + } + def rawOwner0 = rawOwner.getOrElse(abort(s"no owner provided for existential transform over raw parameter: $sym")) + val bound = allBounds(sym) + val sowner = if (isRawParameter(sym)) rawOwner0 else sym.owner + val quantified = sowner.newExistential(name, sym.pos) + + quantified setInfo bound.cloneInfo(quantified) + } + // Higher-kinded existentials are not yet supported, but this is + // tpeHK for when they are: "if a type constructor is expected/allowed, + // tpeHK must be called instead of tpe." + val typeParamTypes = typeParams map (_.tpeHK) + def doSubst(info: Type) = info.subst(rawSyms, typeParamTypes) + + creator(typeParams map (_ modifyInfo doSubst), doSubst(tp)) + } + + /** + * Compute an existential type from hidden symbols `hidden` and type `tp`. + * @param hidden The symbols that will be existentially abstracted + * @param hidden The original type + * @param rawOwner The owner for Java raw types. + */ + final def packSymbols(hidden: List[Symbol], tp: Type, rawOwner: Option[Symbol] = None): Type = + if (hidden.isEmpty) tp + else existentialTransform(hidden, tp, rawOwner)(existentialAbstraction) } diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 4fd86aa8b1..ae2cf09c2e 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -359,8 +359,8 @@ trait StdNames { * be sure to retain the extra dollars. */ def unexpandedName(name: Name): Name = name lastIndexOf "$$" match { - case -1 => name - case idx0 => + case 0 | -1 => name + case idx0 => // Sketchville - We've found $$ but if it's part of $$$ or $$$$ // or something we need to keep the bonus dollars, so e.g. foo$$$outer // has an original name of $outer. diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 410bc738e2..7467ccc6b9 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -1491,6 +1491,11 @@ trait Trees extends api.Trees { self: SymbolTable => /** Substitute symbols in `from` with symbols in `to`. Returns a new * tree using the new symbols and whose Ident and Select nodes are * name-consistent with the new symbols. + * + * Note: This is currently a destructive operation on the original Tree. + * Trees currently assigned a symbol in `from` will be assigned the new symbols + * without copying, and trees that define symbols with an `info` that refer + * a symbol in `from` will have a new type assigned. */ class TreeSymSubstituter(from: List[Symbol], to: List[Symbol]) extends Transformer { val symSubst = new SubstSymMap(from, to) diff --git a/src/reflect/scala/reflect/internal/transform/UnCurry.scala b/src/reflect/scala/reflect/internal/transform/UnCurry.scala index 32d3171b26..1f7638a621 100644 --- a/src/reflect/scala/reflect/internal/transform/UnCurry.scala +++ b/src/reflect/scala/reflect/internal/transform/UnCurry.scala @@ -25,7 +25,14 @@ trait UnCurry { val tp = expandAlias(tp0) tp match { case MethodType(params, MethodType(params1, restpe)) => - apply(MethodType(params ::: params1, restpe)) + // This transformation is described in UnCurryTransformer.dependentParamTypeErasure + val packSymbolsMap = new TypeMap { + // Wrapping in a TypeMap to reuse the code that opts for a fast path if the function is an identity. + def apply(tp: Type): Type = packSymbols(params, tp) + } + val existentiallyAbstractedParam1s = packSymbolsMap.mapOver(params1) + val substitutedResult = restpe.substSym(params1, existentiallyAbstractedParam1s) + apply(MethodType(params ::: existentiallyAbstractedParam1s, substitutedResult)) case MethodType(params, ExistentialType(tparams, restpe @ MethodType(_, _))) => abort("unexpected curried method types with intervening existential") case MethodType(h :: t, restpe) if h.isImplicit => diff --git a/test/files/run/t6715.scala b/test/files/run/t6715.scala new file mode 100644 index 0000000000..07ff34218a --- /dev/null +++ b/test/files/run/t6715.scala @@ -0,0 +1,15 @@ +import scala.reflect.runtime.universe._ + +class A { + def $$ = 1 + def $times = 1 +} + +object Test { + def main(args: Array[String]): Unit = { + val memberSet: Set[String] = typeOf[A].members.map{ _.toString }.toSet + assert(memberSet contains "method *") + assert(memberSet contains "method $$") + assert(! (memberSet contains "method")) + } +} diff --git a/test/files/run/t6793.scala b/test/files/run/t6793.scala new file mode 100644 index 0000000000..0b1f1619af --- /dev/null +++ b/test/files/run/t6793.scala @@ -0,0 +1,9 @@ +package a { class C1(private[a] val v0: String) } +package b { class C2(v1: String) extends a.C1(v1) { def foo = v1 } } + +object Test extends App { + new b.C2("x") + + val c2Fields = classOf[b.C2].getDeclaredFields + assert(c2Fields.size == 1, c2Fields.map(_.getName).toList) +} diff --git a/test/files/run/t6793b.scala b/test/files/run/t6793b.scala new file mode 100644 index 0000000000..cb3f2fb2fa --- /dev/null +++ b/test/files/run/t6793b.scala @@ -0,0 +1,11 @@ +package a { + class C1(val v0: String) + class C2(v1: String) extends a.C1(v1) { def foo = v1 } +} + +object Test extends App { + new a.C2("x") + + val c2Fields = classOf[a.C2].getDeclaredFields + assert(c2Fields.isEmpty, c2Fields.map(_.getName).mkString(", ")) +} diff --git a/test/files/run/t6793c.scala b/test/files/run/t6793c.scala new file mode 100644 index 0000000000..e28c7c81a1 --- /dev/null +++ b/test/files/run/t6793c.scala @@ -0,0 +1,11 @@ +package a { + class C1(private[a] val v0: String) + class C2(v1: String) extends a.C1(v1) { def foo = v1 } +} + +object Test extends App { + new a.C2("x").foo + + val c2Fields = classOf[a.C2].getDeclaredFields + assert(c2Fields.isEmpty, c2Fields.map(_.getName).toList) +} diff --git a/test/files/run/t6900.scala b/test/files/run/t6900.scala new file mode 100644 index 0000000000..a29d388129 --- /dev/null +++ b/test/files/run/t6900.scala @@ -0,0 +1,36 @@ +import annotation.tailrec + +trait Universe { + type T <: AnyRef +} + +final class Bug { + var i = 1 + def stop() = { i -= 1; i < 0 } + // the alias bypasses the fast path in erasures InfoTransformer + // predicated on `TypeMap.noChangeToSymbols` + type Alias = Any + + @tailrec + // So we get two symbols for `universe`, the original on the ValDef + // and a clone in the MethodType of `f`. + def f(universe: Universe, l: Alias): universe.T = { + if (stop()) null.asInstanceOf[universe.T] else f(universe, null) + } + + @tailrec + def g(universe: Universe)(l: Alias): universe.T = { + if (stop()) null.asInstanceOf[universe.T] else g(universe)(l) + } + + @tailrec + def h(universe: Universe)(l: List[universe.T]): List[universe.T] = { + if (stop()) Nil else h(universe)(l) + } +} + +object Test extends App { + assert(new Bug().f(null, null) == null) + assert(new Bug().g(null)(null) == null) + assert(new Bug().h(null)(null) == Nil) +}
\ No newline at end of file diff --git a/test/scaladoc/run/SI-6715.check b/test/scaladoc/run/SI-6715.check new file mode 100644 index 0000000000..619c56180b --- /dev/null +++ b/test/scaladoc/run/SI-6715.check @@ -0,0 +1 @@ +Done. diff --git a/test/scaladoc/run/SI-6715.scala b/test/scaladoc/run/SI-6715.scala new file mode 100644 index 0000000000..92d3376234 --- /dev/null +++ b/test/scaladoc/run/SI-6715.scala @@ -0,0 +1,15 @@ +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + def scaladocSettings = "" + + override def code = "object A { def $$ = 123 }" + + def testModel(rootPackage: Package) = { + import access._ + + val method = rootPackage._object("A")._method("$$") + assert(method != null) + } +} |