diff options
Diffstat (limited to 'src')
72 files changed, 577 insertions, 668 deletions
diff --git a/src/compiler/scala/reflect/reify/phases/Reshape.scala b/src/compiler/scala/reflect/reify/phases/Reshape.scala index 6c073c0b4c..091d42bb6d 100644 --- a/src/compiler/scala/reflect/reify/phases/Reshape.scala +++ b/src/compiler/scala/reflect/reify/phases/Reshape.scala @@ -325,8 +325,7 @@ trait Reshape { if (reifyDebug) println(s"reconstructed lazy val is $vdef1") vdef1::Nil case ddef: DefDef if ddef.symbol.isLazy => - def hasUnitType(sym: Symbol) = (sym.tpe.typeSymbol == UnitClass) && sym.tpe.annotations.isEmpty - if (hasUnitType(ddef.symbol)) { + if (isUnitType(ddef.symbol.info)) { // since lazy values of type Unit don't have val's // we need to create them from scratch toPreTyperLazyVal(ddef) :: Nil diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index 6d24b31531..bf93ad30bc 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -16,16 +16,16 @@ import util.Exceptional.unwrap /** An object that runs Scala code in script files. * - * <p>For example, here is a complete Scala script on Unix:</pre> - * <pre> + * For example, here is a complete Scala script on Unix: + * {{{ * #!/bin/sh * exec scala "$0" "$@" * !# * Console.println("Hello, world!") * args.toList foreach Console.println - * </pre> - * <p>And here is a batch file example on Windows XP:</p> - * <pre> + * }}} + * And here is a batch file example on Windows XP: + * {{{ * ::#! * @echo off * call scala %0 %* @@ -33,7 +33,7 @@ import util.Exceptional.unwrap * ::!# * Console.println("Hello, world!") * args.toList foreach Console.println - * </pre> + * }}} * * @author Lex Spoon * @version 1.0, 15/05/2006 diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index bf53c47e9a..332acf4a26 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -261,7 +261,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { * Create a method based on a Function * * Used both to under `-Ydelambdafy:method` create a lifted function and - * under `-Ydelamdafy:inline` to create the apply method on the anonymous + * under `-Ydelambdafy:inline` to create the apply method on the anonymous * class. * * It creates a method definition with value params cloned from the diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index b76fb3d823..f9e6a12241 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2043,11 +2043,11 @@ self => /** Drop `private` modifier when followed by a qualifier. * Contract `abstract` and `override` to ABSOVERRIDE */ - private def normalizeModifers(mods: Modifiers): Modifiers = + private def normalizeModifiers(mods: Modifiers): Modifiers = if (mods.isPrivate && mods.hasAccessBoundary) - normalizeModifers(mods &~ Flags.PRIVATE) + normalizeModifiers(mods &~ Flags.PRIVATE) else if (mods hasAllFlags (Flags.ABSTRACT | Flags.OVERRIDE)) - normalizeModifers(mods &~ (Flags.ABSTRACT | Flags.OVERRIDE) | Flags.ABSOVERRIDE) + normalizeModifiers(mods &~ (Flags.ABSTRACT | Flags.OVERRIDE) | Flags.ABSOVERRIDE) else mods @@ -2092,7 +2092,7 @@ self => * AccessModifier ::= (private | protected) [AccessQualifier] * }}} */ - def accessModifierOpt(): Modifiers = normalizeModifers { + def accessModifierOpt(): Modifiers = normalizeModifiers { in.token match { case m @ (PRIVATE | PROTECTED) => in.nextToken() ; accessQualifierOpt(Modifiers(flagTokens(m))) case _ => NoMods @@ -2106,7 +2106,7 @@ self => * | override * }}} */ - def modifiers(): Modifiers = normalizeModifers { + def modifiers(): Modifiers = normalizeModifiers { def loop(mods: Modifiers): Modifiers = in.token match { case PRIVATE | PROTECTED => loop(accessQualifierOpt(addMod(mods, flagTokens(in.token), tokenRange(in)))) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 92833d647b..51bb0d3c5b 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -226,7 +226,7 @@ trait Scanners extends ScannersCommon { * RPAREN if region starts with '(' * RBRACKET if region starts with '[' * RBRACE if region starts with '{' - * ARROW if region starts with `case' + * ARROW if region starts with 'case' * STRINGLIT if region is a string interpolation expression starting with '${' * (the STRINGLIT appears twice in succession on the stack iff the * expression is a multiline string literal). @@ -515,7 +515,7 @@ trait Scanners extends ScannersCommon { charLitOr(getIdentRest) else if (isOperatorPart(ch) && (ch != '\\')) charLitOr(getOperatorRest) - else { + else if (!isAtEnd && (ch != SU && ch != CR && ch != LF || isUnicodeEscape)) { getLitChar() if (ch == '\'') { nextChar() @@ -525,6 +525,8 @@ trait Scanners extends ScannersCommon { syntaxError("unclosed character literal") } } + else + syntaxError("unclosed character literal") } fetchSingleQuote() case '.' => @@ -690,7 +692,7 @@ trait Scanners extends ScannersCommon { private def unclosedStringLit(): Unit = syntaxError("unclosed string literal") - private def getRawStringLit(): Unit = { + @tailrec private def getRawStringLit(): Unit = { if (ch == '\"') { nextRawChar() if (isTripleQuote()) { @@ -707,7 +709,7 @@ trait Scanners extends ScannersCommon { } } - @scala.annotation.tailrec private def getStringPart(multiLine: Boolean): Unit = { + @tailrec private def getStringPart(multiLine: Boolean): Unit = { def finishStringPart() = { setStrVal() token = STRINGPART diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 01eff71057..a927097b62 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -2016,7 +2016,7 @@ abstract class GenICode extends SubComponent { * * This could result in unreachable code which has to be cleaned up later, e.g. if the try and all the exception * handlers always end in RETURN then there will be no "normal" flow out of the try/catch/finally. - * Later reachability analysis will remove unreacahble code. + * Later reachability analysis will remove unreachable code. */ def Try(body: Context => Context, handlers: List[(Symbol, TypeKind, Context => Context)], @@ -2060,7 +2060,7 @@ abstract class GenICode extends SubComponent { if (settings.YdisableUnreachablePrevention || !outerCtx.bb.ignore) { if (finalizer != EmptyTree) { val exh = outerCtx.newExceptionHandler(NoSymbol, finalizer.pos) // finalizer covers exception handlers - this.addActiveHandler(exh) // .. and body aswell + this.addActiveHandler(exh) // .. and body as well val exhStartCtx = finalizerCtx.enterExceptionHandler(exh) exhStartCtx.bb killIf outerCtx.bb.ignore val exception = exhStartCtx.makeLocal(finalizer.pos, ThrowableTpe, "exc") diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala index 843648282b..0f17b5d694 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala @@ -20,7 +20,7 @@ abstract class ICodeCheckers { * </p> * <ul> * <li> - * for primitive operations: the type and numer of operands match + * for primitive operations: the type and number of operands match * the type of the operation * </li> * <li> diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 22ac8f84d4..e5eb0b79d5 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -92,8 +92,8 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { def genThrow(expr: Tree): BType = { val thrownKind = tpeTK(expr) - // `throw null` is valid although scala.Null (as defined in src/libray-aux) isn't a subtype of Throwable. - // Similarly for scala.Nothing (again, as defined in src/libray-aux). + // `throw null` is valid although scala.Null (as defined in src/library-aux) isn't a subtype of Throwable. + // Similarly for scala.Nothing (again, as defined in src/library-aux). assert(thrownKind.isNullType || thrownKind.isNothingType || thrownKind.asClassBType.isSubtypeOf(ThrowableReference).get) genLoad(expr, thrownKind) lineNumber(expr) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala index c8ba0d9dbc..aff2d2d8c9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala @@ -1144,7 +1144,7 @@ object BTypes { * The map is indexed by the string s"$name$descriptor" (to * disambiguate overloads). * - * @param warning Contains an warning message if an error occured when building this + * @param warning Contains an warning message if an error occurred when building this * InlineInfo, for example if some classfile could not be found on * the classpath. This warning can be reported later by the inliner. */ diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 7096f16d75..7883ce7ffa 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -492,8 +492,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => * generic classes or interfaces. * * @param superName the internal of name of the super class. For interfaces, - * the super class is {@link Object}. May be <tt>null</tt>, but - * only for the {@link Object} class. + * the super class is [[Object]]. May be <tt>null</tt>, but + * only for the [[Object]] class. * * @param interfaces the internal names of the class's interfaces (see * {@link Type#getInternalName() getInternalName}). May be @@ -529,6 +529,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => case e: java.lang.RuntimeException if e.getMessage != null && (e.getMessage contains "too large!") => reporter.error(sym.pos, s"Could not write class $jclassName because it exceeds JVM code size limits. ${e.getMessage}") + case e: java.io.IOException if e.getMessage != null && (e.getMessage contains "File name too long") => + reporter.error(sym.pos, e.getMessage + "\n" + + "This can happen on some encrypted or legacy file systems. Please see SI-3623 for more details.") + } } @@ -2693,7 +2697,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => case CMPG => (kind: @unchecked) match { case FLOAT => emit(Opcodes.FCMPG) - case DOUBLE => emit(Opcodes.DCMPL) // TODO bug? why not DCMPG? http://docs.oracle.com/javase/specs/jvms/se5.0/html/Instructions2.doc3.html + case DOUBLE => emit(Opcodes.DCMPL) // TODO bug? why not DCMPG? http://docs.oracle.com/javase/specs/jvms/se6/html/Instructions2.doc3.html } } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala index c50648acd9..f1ac703532 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala @@ -1,7 +1,7 @@ package scala.tools.nsc.backend.jvm /** - * Summary on the ASM ananlyzer framework + * Summary on the ASM analyzer framework * -------------------------------------- * * Value diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala index 5d3b7ff272..fb7dd16909 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala @@ -367,7 +367,7 @@ class ClosureOptimizer[BT <: BTypes](val btypes: BT) { } /** - * Stores a local varaible index the opcode offset required for operating on that variable. + * Stores a local variable index the opcode offset required for operating on that variable. * * The xLOAD / xSTORE opcodes are in the following sequence: I, L, F, D, A, so the offset for * a local variable holding a reference (`A`) is 4. See also method `getOpcode` in [[scala.tools.asm.Type]]. diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala index 20256ca63b..baa747492f 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala @@ -341,7 +341,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { clonedInstructions.insert(argStores) - // label for the exit of the inlined functions. xRETURNs are rplaced by GOTOs to this label. + // label for the exit of the inlined functions. xRETURNs are replaced by GOTOs to this label. val postCallLabel = newLabelNode clonedInstructions.add(postCallLabel) @@ -704,9 +704,9 @@ class Inliner[BT <: BTypes](val btypes: BT) { // - a method name+type // // execution [3] - // - resolve the CSP, yielding the boostrap method handle, the static args and the name+type + // - resolve the CSP, yielding the bootstrap method handle, the static args and the name+type // - resolution entails accessibility checking [4] - // - execute the `invoke` method of the boostrap method handle (which is signature polymorphic, check its javadoc) + // - execute the `invoke` method of the bootstrap method handle (which is signature polymorphic, check its javadoc) // - the descriptor for the call is made up from the actual arguments on the stack: // - the first parameters are "MethodHandles.Lookup, String, MethodType", then the types of the constant arguments, // - the return type is CallSite diff --git a/src/compiler/scala/tools/nsc/io/Jar.scala b/src/compiler/scala/tools/nsc/io/Jar.scala index 2967f67e9c..efb026cdff 100644 --- a/src/compiler/scala/tools/nsc/io/Jar.scala +++ b/src/compiler/scala/tools/nsc/io/Jar.scala @@ -154,7 +154,7 @@ object Jar { def update(key: Attributes.Name, value: String) = attrs.put(key, value) } - // See http://download.java.net/jdk7/docs/api/java/nio/file/Path.html + // See http://docs.oracle.com/javase/7/docs/api/java/nio/file/Path.html // for some ideas. private val ZipMagicNumber = List[Byte](80, 75, 3, 4) private def magicNumberIsZip(f: Path) = f.isFile && (f.toFile.bytes().take(4).toList == ZipMagicNumber) diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index 79776485de..82e7c76409 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -111,7 +111,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => impl setInfo new LazyImplClassType(iface) } - /** Return the implementation class of a trait; create a new one of one does not yet exist */ + /** Return the implementation class of a trait; create a new one if one does not yet exist */ def implClass(iface: Symbol): Symbol = { iface.info diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 7c66bda46b..48eb878e2a 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -137,7 +137,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { * and thus may only be accessed from value or method definitions owned by the current class * (ie there's no point drilling down into nested classes). * - * (d) regarding candidates in (b), they are accesible from all places listed in (c) and in addition + * (d) regarding candidates in (b), they are accessible from all places listed in (c) and in addition * from nested classes (nested at any number of levels). * * In all cases, we're done with traversing as soon as all candidates have been ruled out. @@ -396,9 +396,9 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { } if (stat1 eq stat) { - assert(ctorParams(genericClazz).length == constrInfo.constrParams.length) + assert(ctorParams(genericClazz).length == primaryConstrParams.length) // this is just to make private fields public - (new specializeTypes.ImplementationAdapter(ctorParams(genericClazz), constrInfo.constrParams, null, true))(stat1) + (new specializeTypes.ImplementationAdapter(ctorParams(genericClazz), primaryConstrParams, null, true))(stat1) val stat2 = rewriteArrayUpdate(stat1) // statements coming from the original class need retyping in the current context @@ -435,16 +435,16 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { // postfix = postfix.tail // } - if (shouldGuard && usesSpecializedField && stats.nonEmpty) { + if (guardSpecializedFieldInit && intoConstructor.usesSpecializedField && stats.nonEmpty) { // save them for duplication in the specialized subclass guardedCtorStats(clazz) = stats - ctorParams(clazz) = constrInfo.constrParams + ctorParams(clazz) = primaryConstrParams val tree = If( Apply( CODE.NOT ( - Apply(gen.mkAttributedRef(specializedFlag), List())), + Apply(gen.mkAttributedRef(hasSpecializedFieldsSym), List())), List()), Block(stats, Literal(Constant(()))), EmptyTree) @@ -476,27 +476,17 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { val stats = impl.body // the transformed template body val localTyper = typer.atOwner(impl, clazz) - val specializedFlag: Symbol = clazz.info.decl(nme.SPECIALIZED_INSTANCE) - val shouldGuard = (specializedFlag != NoSymbol) && !clazz.hasFlag(SPECIALIZED) - - val isDelayedInitSubclass = (clazz isSubClass DelayedInitClass) - - case class ConstrInfo( - constr: DefDef, // The primary constructor - constrParams: List[Symbol], // ... and its parameters - constrBody: Block // ... and its body - ) - // decompose primary constructor into the three entities above. - val constrInfo: ConstrInfo = { - val ddef = (stats find (_.symbol.isPrimaryConstructor)) - ddef match { - case Some(ddef @ DefDef(_, _, _, List(vparams), _, rhs @ Block(_, _))) => - ConstrInfo(ddef, vparams map (_.symbol), rhs) - case x => - abort("no constructor in template: impl = " + impl) - } - } - import constrInfo._ + val hasSpecializedFieldsSym = clazz.info.decl(nme.SPECIALIZED_INSTANCE) + // The constructor of a non-specialized class that has specialized subclasses + // should use `q"${hasSpecializedFieldsSym}()"` to guard the initialization of specialized fields. + val guardSpecializedFieldInit = (hasSpecializedFieldsSym != NoSymbol) && !clazz.hasFlag(SPECIALIZED) + + val isDelayedInitSubclass = clazz isSubClass DelayedInitClass + + // find and dissect primary constructor + val (primaryConstr, primaryConstrParams, primaryConstrBody) = stats collectFirst { + case dd@DefDef(_, _, _, vps :: Nil, _, rhs: Block) if dd.symbol.isPrimaryConstructor => (dd, vps map (_.symbol), rhs) + } getOrElse abort("no constructor in template: impl = " + impl) // The parameter accessor fields which are members of the class val paramAccessors = clazz.constrParamAccessors @@ -509,27 +499,26 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { def parameterNamed(name: Name): Symbol = { def matchesName(param: Symbol) = param.name == name || param.name.startsWith(name + nme.NAME_JOIN_STRING) - (constrParams filter matchesName) match { - case Nil => abort(name + " not in " + constrParams) + primaryConstrParams filter matchesName match { + case Nil => abort(name + " not in " + primaryConstrParams) case p :: _ => p } } - /* - * `usesSpecializedField` makes a difference in deciding whether constructor-statements - * should be guarded in a `shouldGuard` class, ie in a class that's the generic super-class of - * one or more specialized sub-classes. - * - * Given that `usesSpecializedField` isn't read for any other purpose than the one described above, - * we skip setting `usesSpecializedField` in case the current class isn't `shouldGuard` to start with. - * That way, trips to a map in `specializeTypes` are saved. - */ - var usesSpecializedField: Boolean = false - // A transformer for expressions that go into the constructor - private class IntoCtorTransformer extends Transformer { - - private def isParamRef(sym: Symbol) = (sym.isParamAccessor && sym.owner == clazz) + object intoConstructor extends Transformer { + /* + * `usesSpecializedField` makes a difference in deciding whether constructor-statements + * should be guarded in a `guardSpecializedFieldInit` class, ie in a class that's the generic super-class of + * one or more specialized sub-classes. + * + * Given that `usesSpecializedField` isn't read for any other purpose than the one described above, + * we skip setting `usesSpecializedField` in case the current class isn't `guardSpecializedFieldInit` to start with. + * That way, trips to a map in `specializeTypes` are saved. + */ + var usesSpecializedField: Boolean = false + + private def isParamRef(sym: Symbol) = sym.isParamAccessor && sym.owner == clazz // Terminology: a stationary location is never written after being read. private def isStationaryParamRef(sym: Symbol) = ( @@ -548,10 +537,9 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { * (b.2) the constructor in the specialized (sub-)class. * (c) isn't part of a DelayedInit subclass. */ - private def canBeSupplanted(sym: Symbol) = (!isDelayedInitSubclass && isStationaryParamRef(sym) && !possiblySpecialized(sym)) + private def canBeSupplanted(sym: Symbol) = !isDelayedInitSubclass && isStationaryParamRef(sym) && !possiblySpecialized(sym) override def transform(tree: Tree): Tree = tree match { - case Apply(Select(This(_), _), List()) => // references to parameter accessor methods of own class become references to parameters // outer accessors become references to $outer parameter @@ -566,7 +554,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { // references to parameter accessor field of own class become references to parameters gen.mkAttributedIdent(parameter(tree.symbol)) setPos tree.pos - case Select(_, _) if shouldGuard => // reasoning behind this guard in the docu of `usesSpecializedField` + case Select(_, _) if guardSpecializedFieldInit => // reasoning behind this guard in the docu of `usesSpecializedField` if (possiblySpecialized(tree.symbol)) { usesSpecializedField = true } @@ -576,18 +564,10 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { super.transform(tree) } - } - - private val intoConstructorTransformer = new IntoCtorTransformer - - // Move tree into constructor, take care of changing owner from `oldowner` to constructor symbol - def intoConstructor(oldowner: Symbol, tree: Tree) = - intoConstructorTransformer transform tree.changeOwner(oldowner -> constr.symbol) - - // Should tree be moved in front of super constructor call? - def canBeMoved(tree: Tree) = tree match { - case ValDef(mods, _, _, _) => (mods hasFlag PRESUPER | PARAMACCESSOR) - case _ => false + // Move tree into constructor, take care of changing owner from `oldowner` to constructor symbol + def apply(oldowner: Symbol, tree: Tree) = + if (tree eq EmptyTree) tree + else transform(tree.changeOwner(oldowner -> primaryConstr.symbol)) } // Create an assignment to class field `to` with rhs `from` @@ -629,10 +609,10 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { val classInitStatBuf = new ListBuffer[Tree] // generate code to copy pre-initialized fields - for (stat <- constrBody.stats) { + for (stat <- primaryConstrBody.stats) { constrStatBuf += stat stat match { - case ValDef(mods, name, _, _) if (mods hasFlag PRESUPER) => + case ValDef(mods, name, _, _) if mods hasFlag PRESUPER => // stat is the constructor-local definition of the field value val fields = presupers filter (_.getterName == name) assert(fields.length == 1) @@ -643,45 +623,48 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { } } - // Triage all template definitions to go into defBuf/auxConstructorBuf, constrStatBuf, or constrPrefixBuf. - for (stat <- stats) stat match { - case DefDef(_,_,_,_,_,rhs) => - // methods with constant result type get literals as their body - // all methods except the primary constructor go into template - stat.symbol.tpe match { - case MethodType(List(), tp @ ConstantType(c)) => - defBuf += deriveDefDef(stat)(Literal(c) setPos _.pos setType tp) - case _ => - if (stat.symbol.isPrimaryConstructor) () - else if (stat.symbol.isConstructor) auxConstructorBuf += stat - else defBuf += stat - } - case ValDef(mods, _, _, rhs) if !mods.hasStaticFlag => + + for (stat <- stats) { + val statSym = stat.symbol + + stat match { + // recurse on class definition, store in defBuf + case _: ClassDef => defBuf += new ConstructorTransformer(unit).transform(stat) + + // methods (except primary constructor) go into template + // (non-primary ctors --> auxConstructorBuf / regular defs --> defBuf) + case _: DefDef if statSym.isPrimaryConstructor => () + case _: DefDef if statSym.isConstructor => auxConstructorBuf += stat + case _: DefDef => defBuf += stat + // val defs with constant right-hand sides are eliminated. - // for all other val defs, an empty valdef goes into the template and - // the initializer goes as an assignment into the constructor - // if the val def is an early initialized or a parameter accessor, it goes - // before the superclass constructor call, otherwise it goes after. - // Lazy vals don't get the assignment in the constructor. - if (!stat.symbol.tpe.isInstanceOf[ConstantType]) { - if (rhs != EmptyTree && !stat.symbol.isLazy) { - val rhs1 = intoConstructor(stat.symbol, rhs) - (if (canBeMoved(stat)) constrPrefixBuf else constrStatBuf) += mkAssign( - stat.symbol, rhs1) + case _: ValDef if statSym.info.isInstanceOf[ConstantType] => () + + // For all other val defs, an empty valdef goes into the template. + // Additionally, non-lazy vals are initialized by an assignment in: + // - the class initializer (static), + // - the constructor, before the super call (early initialized or a parameter accessor), + // - the constructor, after the super call (regular val). + case ValDef(mods, _, _, rhs) => + val initializingRhs = + if (statSym.isLazy) EmptyTree + else if (!mods.hasStaticFlag) intoConstructor(statSym, rhs) + else rhs + + if (initializingRhs ne EmptyTree) { + val initPhase = + if (mods hasFlag STATIC) classInitStatBuf + else if (mods hasFlag PRESUPER | PARAMACCESSOR) constrPrefixBuf + else constrStatBuf + + initPhase += mkAssign(statSym, initializingRhs) } + defBuf += deriveValDef(stat)(_ => EmptyTree) - } - case ValDef(_, _, _, rhs) => - // Add static initializer statements to classInitStatBuf and remove the rhs from the val def. - classInitStatBuf += mkAssign(stat.symbol, rhs) - defBuf += deriveValDef(stat)(_ => EmptyTree) - - case ClassDef(_, _, _, _) => - // classes are treated recursively, and left in the template - defBuf += new ConstructorTransformer(unit).transform(stat) - case _ => + // all other statements go into the constructor - constrStatBuf += intoConstructor(impl.symbol, stat) + case _ => constrStatBuf += intoConstructor(impl.symbol, stat) + } } populateOmittables() @@ -716,12 +699,12 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { rewriteDelayedInit() // Assemble final constructor - defBuf += deriveDefDef(constr)(_ => + defBuf += deriveDefDef(primaryConstr)(_ => treeCopy.Block( - constrBody, + primaryConstrBody, paramInits ::: constrPrefixBuf.toList ::: uptoSuperStats ::: guardSpecializedInitializer(remainingConstrStats), - constrBody.expr)) + primaryConstrBody.expr)) // Followed by any auxiliary constructors defBuf ++= auxConstructorBuf @@ -732,6 +715,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { // Eliminate all field definitions that can be dropped from template val templateWithoutOmittables: Template = deriveTemplate(impl)(_ => defBuf.toList filter (stat => mustBeKept(stat.symbol))) + // Add the static initializers val transformed: Template = addStaticInits(templateWithoutOmittables, classInitStatBuf, localTyper) diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala index ddf003bb98..33fd5d0461 100644 --- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala +++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala @@ -281,7 +281,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre val parents = addSerializable(abstractFunctionErasedType) val funOwner = originalFunction.symbol.owner - // TODO harmonize the naming of delamdafy anon-fun classes with those spun up by Uncurry + // TODO harmonize the naming of delambdafy anon-fun classes with those spun up by Uncurry // - make `anonClass.isAnonymousClass` true. // - use `newAnonymousClassSymbol` or push the required variations into a similar factory method // - reinstate the assertion in `Erasure.resolveAnonymousBridgeClash` diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index a079a76ce7..00a994fe87 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -778,7 +778,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { val defSym = clazz.newMethod(nme.newLazyValSlowComputeName(lzyVal.name.toTermName), lzyVal.pos, PRIVATE) val params = defSym newSyntheticValueParams args.map(_.symbol.tpe) defSym setInfoAndEnter MethodType(params, lzyVal.tpe.resultType) - val rhs: Tree = (gen.mkSynchronizedCheck(attrThis, cond, syncBody, stats)).changeOwner(currentOwner -> defSym) + val rhs: Tree = gen.mkSynchronizedCheck(attrThis, cond, syncBody, stats).changeOwner(currentOwner -> defSym) val strictSubst = new TreeSymSubstituterWithCopying(args.map(_.symbol), params) addDef(position(defSym), DefDef(defSym, strictSubst(BLOCK(rhs, retVal)))) defSym diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 72e2174bf8..57639a94c7 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -582,6 +582,7 @@ abstract class UnCurry extends InfoTransform } case dd @ DefDef(_, _, _, vparamss0, _, rhs0) => + val ddSym = dd.symbol val (newParamss, newRhs): (List[List[ValDef]], Tree) = if (dependentParamTypeErasure isDependent dd) dependentParamTypeErasure erase dd @@ -593,11 +594,22 @@ abstract class UnCurry extends InfoTransform (vparamss1, rhs0) } + // A no-arg method with ConstantType result type can safely be reduced to the corresponding Literal + // (only pure methods are typed as ConstantType). We could also do this for methods with arguments, + // after ensuring the arguments are not referenced. + val literalRhsIfConst = + if (newParamss.head.isEmpty) { // We know newParamss.length == 1 from above + ddSym.info.resultType match { + case tp@ConstantType(value) => Literal(value) setType tp setPos newRhs.pos // inlining of gen.mkAttributedQualifier(tp) + case _ => newRhs + } + } else newRhs + val flatdd = copyDefDef(dd)( vparamss = newParamss, - rhs = nonLocalReturnKeys get dd.symbol match { - case Some(k) => atPos(newRhs.pos)(nonLocalReturnTry(newRhs, k, dd.symbol)) - case None => newRhs + rhs = nonLocalReturnKeys get ddSym match { + case Some(k) => atPos(newRhs.pos)(nonLocalReturnTry(literalRhsIfConst, k, ddSym)) + case None => literalRhsIfConst } ) addJavaVarargsForwarders(dd, flatdd) @@ -691,9 +703,46 @@ abstract class UnCurry extends InfoTransform // declared type and assign this to a synthetic val. Later, we'll patch // the method body to refer to this, rather than the parameter. val tempVal: ValDef = { + // SI-9442: using the "uncurry-erased" type (the one after the uncurry phase) can lead to incorrect + // tree transformations. For example, compiling: + // ``` + // def foo(c: Ctx)(l: c.Tree): Unit = { + // val l2: c.Tree = l + // } + // ``` + // Results in the following AST: + // ``` + // def foo(c: Ctx, l: Ctx#Tree): Unit = { + // val l$1: Ctx#Tree = l.asInstanceOf[Ctx#Tree] + // val l2: c.Tree = l$1 // no, not really, it's not. + // } + // ``` + // Of course, this is incorrect, since `l$1` has type `Ctx#Tree`, which is not a subtype of `c.Tree`. + // + // So what we need to do is to use the pre-uncurry type when creating `l$1`, which is `c.Tree` and is + // correct. Now, there are two additional problems: + // 1. when varargs and byname params are involved, the uncurry transformation desugares these special + // cases to actual typerefs, eg: + // ``` + // T* ~> Seq[T] (Scala-defined varargs) + // T* ~> Array[T] (Java-defined varargs) + // =>T ~> Function0[T] (by name params) + // ``` + // we use the DesugaredParameterType object (defined in scala.reflect.internal.transform.UnCurry) + // to redo this desugaring manually here + // 2. the type needs to be normalized, since `gen.mkCast` checks this (no HK here, just aliases have + // to be expanded before handing the type to `gen.mkAttributedCast`, which calls `gen.mkCast`) + val info0 = + enteringUncurry(p.symbol.info) match { + case DesugaredParameterType(desugaredTpe) => + desugaredTpe + case tpe => + tpe + } + val info = info0.normalize val tempValName = unit freshTermName (p.name + "$") - 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))) + val newSym = dd.symbol.newTermSymbol(tempValName, p.pos, SYNTHETIC).setInfo(info) + atPos(p.pos)(ValDef(newSym, gen.mkAttributedCast(Ident(p.symbol), info))) } Packed(newParam, tempVal) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala index 8bcd5e6f12..2b6a4c763a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala @@ -44,7 +44,7 @@ import scala.language.postfixOps * which is essentially the intersection of X and |P|, where |P| is * the erasure of P. If XR <: P, then no warning is emitted. * - * We evaluate "X with conform to P" by checking `X <: P_wild, where + * We evaluate "X with conform to P" by checking `X <: P_wild`, where * P_wild is the result of substituting wildcard types in place of * pattern type variables. This is intentionally stricter than * (X matchesPattern P), see SI-8597 for motivating test cases. diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index b0bd9977a8..c9d3b3da96 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -1105,7 +1105,7 @@ trait ContextErrors { def GetterDefinedTwiceError(getter: Symbol) = issueSymbolTypeError(getter, getter+" is defined twice") - def ValOrValWithSetterSuffixError(tree: Tree) = + def ValOrVarWithSetterSuffixError(tree: Tree) = issueNormalTypeError(tree, "Names of vals or vars may not end in `_='") def PrivateThisCaseClassParameterError(tree: Tree) = @@ -1212,7 +1212,8 @@ trait ContextErrors { import definitions._ - def AmbiguousImplicitError(info1: ImplicitInfo, info2: ImplicitInfo, + def AmbiguousImplicitError(info1: ImplicitInfo, tree1: Tree, + info2: ImplicitInfo, tree2: Tree, pre1: String, pre2: String, trailer: String) (isView: Boolean, pt: Type, tree: Tree)(implicit context0: Context) = { if (!info1.tpe.isErroneous && !info2.tpe.isErroneous) { @@ -1248,10 +1249,20 @@ trait ContextErrors { if (explanation == "") "" else "\n" + explanation ) } + + def treeTypeArgs(annotatedTree: Tree) = annotatedTree match { + case TypeApply(_, args) => args.map(_.toString) + case _ => Nil + } + context.issueAmbiguousError(AmbiguousImplicitTypeError(tree, - if (isView) viewMsg - else s"ambiguous implicit values:\n${coreMsg}match expected type $pt") - ) + (tree1.symbol, tree2.symbol) match { + case (ImplicitAmbiguousMsg(msg), _) => msg.format(treeTypeArgs(tree1)) + case (_, ImplicitAmbiguousMsg(msg)) => msg.format(treeTypeArgs(tree2)) + case (_, _) if isView => viewMsg + case (_, _) => s"ambiguous implicit values:\n${coreMsg}match expected type $pt" + } + )) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 196b137a3e..2fb3ae41e2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -110,10 +110,10 @@ trait Implicits { * Ignore their constr field! The list of type constraints returned along with each tree specifies the constraints that * must be met by the corresponding type parameter in `tpars` (for the returned implicit view to be valid). * - * @arg tp from-type for the implicit conversion - * @arg context search implicits here - * @arg tpars symbols that should be considered free type variables - * (implicit search should not try to solve them, just track their constraints) + * @param tp from-type for the implicit conversion + * @param context search implicits here + * @param tpars symbols that should be considered free type variables + * (implicit search should not try to solve them, just track their constraints) */ def allViewsFrom(tp: Type, context: Context, tpars: List[Symbol]): List[(SearchResult, List[TypeConstraint])] = { // my untouchable typevars are better than yours (they can't be constrained by them) @@ -324,8 +324,10 @@ trait Implicits { */ class ImplicitSearch(tree: Tree, pt: Type, isView: Boolean, context0: Context, pos0: Position = NoPosition) extends Typer(context0) with ImplicitsContextErrors { val searchId = implicitSearchId() - private def typingLog(what: String, msg: => String) = - typingStack.printTyping(tree, f"[search #$searchId] $what $msg") + private def typingLog(what: String, msg: => String) = { + if (printingOk(tree)) + typingStack.printTyping(f"[search #$searchId] $what $msg") + } import infer._ if (Statistics.canEnable) Statistics.incCounter(implicitSearchCount) @@ -885,7 +887,7 @@ trait Implicits { * - find the most likely one * - if it matches, forget about all others it improves upon */ - @tailrec private def rankImplicits(pending: Infos, acc: Infos): Infos = pending match { + @tailrec private def rankImplicits(pending: Infos, acc: List[(SearchResult, ImplicitInfo)]): List[(SearchResult, ImplicitInfo)] = pending match { case Nil => acc case firstPending :: otherPending => def firstPendingImproves(alt: ImplicitInfo) = @@ -912,7 +914,7 @@ trait Implicits { val pendingImprovingBest = undoLog undo { otherPending filterNot firstPendingImproves } - rankImplicits(pendingImprovingBest, firstPending :: acc) + rankImplicits(pendingImprovingBest, (newBest, firstPending) :: acc) } } @@ -928,14 +930,14 @@ trait Implicits { // So if there is any element not improved upon by the first it is an error. rankImplicits(eligible, Nil) match { case Nil => () - case chosen :: rest => - rest find (alt => !improves(chosen, alt)) match { - case Some(competing) => - AmbiguousImplicitError(chosen, competing, "both", "and", "")(isView, pt, tree)(context) + case (chosenResult, chosenInfo) :: rest => + rest find { case (_, alt) => !improves(chosenInfo, alt) } match { + case Some((competingResult, competingInfo)) => + AmbiguousImplicitError(chosenInfo, chosenResult.tree, competingInfo, competingResult.tree, "both", "and", "")(isView, pt, tree)(context) return AmbiguousSearchFailure // Stop the search once ambiguity is encountered, see t4457_2.scala case _ => - if (isView) chosen.useCountView += 1 - else chosen.useCountArg += 1 + if (isView) chosenInfo.useCountView += 1 + else chosenInfo.useCountArg += 1 } } @@ -1445,9 +1447,9 @@ trait Implicits { } } - object ImplicitNotFoundMsg { - def unapply(sym: Symbol): Option[(Message)] = sym.implicitNotFoundMsg match { - case Some(m) => Some(new Message(sym, m)) + class ImplicitAnnotationMsg(f: Symbol => Option[String], clazz: Symbol, annotationName: String) { + def unapply(sym: Symbol): Option[(Message)] = f(sym) match { + case Some(m) => Some(new Message(sym, m, annotationName)) case None if sym.isAliasType => // perform exactly one step of dealiasing // this is necessary because ClassManifests are now aliased to ClassTags @@ -1459,41 +1461,45 @@ trait Implicits { // check the message's syntax: should be a string literal that may contain occurrences of the string "${X}", // where `X` refers to a type parameter of `sym` def check(sym: Symbol): Option[String] = - sym.getAnnotation(ImplicitNotFoundClass).flatMap(_.stringArg(0) match { - case Some(m) => new Message(sym, m).validate - case None => Some("Missing argument `msg` on implicitNotFound annotation.") + sym.getAnnotation(clazz).flatMap(_.stringArg(0) match { + case Some(m) => new Message(sym, m, annotationName).validate + case None => Some(s"Missing argument `msg` on $annotationName annotation.") }) + } + + object ImplicitNotFoundMsg extends ImplicitAnnotationMsg(_.implicitNotFoundMsg, ImplicitNotFoundClass, "implicitNotFound") + object ImplicitAmbiguousMsg extends ImplicitAnnotationMsg(_.implicitAmbiguousMsg, ImplicitAmbiguousClass, "implicitAmbiguous") + + class Message(sym: Symbol, msg: String, annotationName: String) { // http://dcsobral.blogspot.com/2010/01/string-interpolation-in-scala-with.html private val Intersobralator = """\$\{\s*([^}\s]+)\s*\}""".r - class Message(sym: Symbol, msg: String) { - private def interpolate(text: String, vars: Map[String, String]) = - Intersobralator.replaceAllIn(text, (_: Regex.Match) match { - case Regex.Groups(v) => Regex quoteReplacement vars.getOrElse(v, "") + private def interpolate(text: String, vars: Map[String, String]) = + Intersobralator.replaceAllIn(text, (_: Regex.Match) match { + case Regex.Groups(v) => Regex quoteReplacement vars.getOrElse(v, "") // #3915: need to quote replacement string since it may include $'s (such as the interpreter's $iw) - }) + }) - private lazy val typeParamNames: List[String] = sym.typeParams.map(_.decodedName) - private def typeArgsAtSym(paramTp: Type) = paramTp.baseType(sym).typeArgs + private lazy val typeParamNames: List[String] = sym.typeParams.map(_.decodedName) + private def typeArgsAtSym(paramTp: Type) = paramTp.baseType(sym).typeArgs - def format(paramName: Name, paramTp: Type): String = format(typeArgsAtSym(paramTp) map (_.toString)) + def format(paramName: Name, paramTp: Type): String = format(typeArgsAtSym(paramTp) map (_.toString)) - def format(typeArgs: List[String]): String = - interpolate(msg, Map((typeParamNames zip typeArgs): _*)) // TODO: give access to the name and type of the implicit argument, etc? + def format(typeArgs: List[String]): String = + interpolate(msg, Map((typeParamNames zip typeArgs): _*)) // TODO: give access to the name and type of the implicit argument, etc? - def validate: Option[String] = { - val refs = Intersobralator.findAllMatchIn(msg).map(_ group 1).toSet - val decls = typeParamNames.toSet + def validate: Option[String] = { + val refs = Intersobralator.findAllMatchIn(msg).map(_ group 1).toSet + val decls = typeParamNames.toSet - (refs &~ decls) match { - case s if s.isEmpty => None - case unboundNames => - val singular = unboundNames.size == 1 - val ess = if (singular) "" else "s" - val bee = if (singular) "is" else "are" - Some(s"The type parameter$ess ${unboundNames mkString ", "} referenced in the message of the @implicitNotFound annotation $bee not defined by $sym.") - } + (refs &~ decls) match { + case s if s.isEmpty => None + case unboundNames => + val singular = unboundNames.size == 1 + val ess = if (singular) "" else "s" + val bee = if (singular) "is" else "are" + Some(s"The type parameter$ess ${unboundNames mkString ", "} referenced in the message of the @$annotationName annotation $bee not defined by $sym.") } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index bf705e89ad..a5fdbb5148 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1375,7 +1375,7 @@ trait Infer extends Checkable { * Otherwise, if there is no best alternative, error. * * @param argtpes0 contains the argument types. If an argument is named, as - * "a = 3", the corresponding type is `NamedType("a", Int)'. If the name + * "a = 3", the corresponding type is `NamedType("a", Int)`. If the name * of some NamedType does not exist in an alternative's parameter names, * the type is replaces by `Unit`, i.e. the argument is treated as an * assignment expression. diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 99dd81c7e2..3ed128cbc5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -55,6 +55,13 @@ trait Macros extends MacroRuntimes with Traces with Helpers { def globalSettings = global.settings + /** Obtains a `ClassLoader` instance used for macro expansion. + * + * By default a new `ScalaClassLoader` is created using the classpath + * from global and the classloader of self as parent. + * + * Mirrors with runtime definitions (e.g. Repl) need to adjust this method. + */ protected def findMacroClassLoader(): ClassLoader = { val classpath = global.classPath.asURLs macroLogVerbose("macro classloader: initializing from -cp: %s".format(classpath)) @@ -658,7 +665,7 @@ trait Macros extends MacroRuntimes with Traces with Helpers { // // Situation #2 requires measures to be taken. If we're in it, then noone's going to help us infer // the undetermined type params. Therefore we need to do something ourselves or otherwise this - // expandee will forever remaing not expanded (see SI-5692). A traditional way out of this conundrum + // expandee will forever remain not expanded (see SI-5692). A traditional way out of this conundrum // is to call `instantiate` and let the inferencer try to find the way out. It works for simple cases, // but sometimes, if the inferencer lacks information, it will be forced to approximate. // diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index f3856db552..f3632b144d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -134,28 +134,28 @@ trait MethodSynthesis { ImplicitClassWrapper(tree).createAndEnterSymbol() } - def enterGetterSetter(tree: ValDef) { - val ValDef(mods, name, _, _) = tree - if (nme.isSetterName(name)) - ValOrValWithSetterSuffixError(tree) - - tree.symbol = ( - if (mods.isLazy) { + // TODO: see if we can link symbol creation & tree derivation by sharing the Field/Getter/Setter factories + def enterGetterSetter(tree: ValDef): Unit = { + tree.symbol = + if (tree.mods.isLazy) { val lazyValGetter = LazyValGetter(tree).createAndEnterSymbol() enterLazyVal(tree, lazyValGetter) } else { - if (mods.isPrivateLocal) - PrivateThisCaseClassParameterError(tree) - val getter = Getter(tree).createAndEnterSymbol() + val getter = Getter(tree) + val getterSym = getter.createAndEnterSymbol() + // Create the setter if necessary. - if (mods.isMutable) + if (getter.needsSetter) Setter(tree).createAndEnterSymbol() - // If abstract, the tree gets the getter's symbol. Otherwise, create a field. - if (mods.isDeferred) getter setPos tree.pos + // If the getter's abstract the tree gets the getter's symbol, + // otherwise, create a field (assume the getter requires storage). + // NOTE: we cannot look at symbol info, since we're in the process of deriving them + // (luckily, they only matter for lazy vals, which we've ruled out in this else branch, + // and `doNotDeriveField` will skip them if `!mods.isLazy`) + if (Field.noFieldFor(tree)) getterSym setPos tree.pos else enterStrictVal(tree) } - ) enterBeans(tree) } @@ -177,11 +177,11 @@ trait MethodSynthesis { } def addDerivedTrees(typer: Typer, stat: Tree): List[Tree] = stat match { - case vd @ ValDef(mods, name, tpt, rhs) if !noFinishGetterSetter(vd) => + case vd @ ValDef(mods, name, tpt, rhs) if deriveAccessors(vd) && !vd.symbol.isModuleVar => // If we don't save the annotations, they seem to wander off. val annotations = stat.symbol.initialize.annotations val trees = ( - allValDefDerived(vd) + (field(vd) ::: standardAccessors(vd) ::: beanAccessors(vd)) map (acc => atPos(vd.pos.focus)(acc derive annotations)) filterNot (_ eq EmptyTree) ) @@ -221,11 +221,14 @@ trait MethodSynthesis { stat :: Nil } - def standardAccessors(vd: ValDef): List[DerivedFromValDef] = ( - if (vd.mods.isMutable && !vd.mods.isLazy) List(Getter(vd), Setter(vd)) - else if (vd.mods.isLazy) List(LazyValGetter(vd)) - else List(Getter(vd)) - ) + def standardAccessors(vd: ValDef): List[DerivedFromValDef] = + if (vd.mods.isLazy) List(LazyValGetter(vd)) + else { + val getter = Getter(vd) + if (getter.needsSetter) List(getter, Setter(vd)) + else List(getter) + } + def beanAccessors(vd: ValDef): List[DerivedFromValDef] = { val setter = if (vd.mods.isMutable) List(BeanSetter(vd)) else Nil if (vd.symbol hasAnnotation BeanPropertyAttr) @@ -234,15 +237,8 @@ trait MethodSynthesis { BooleanBeanGetter(vd) :: setter else Nil } - def allValDefDerived(vd: ValDef) = { - val field = if (vd.mods.isDeferred || (vd.mods.isLazy && hasUnitType(vd.symbol))) Nil - else List(Field(vd)) - field ::: standardAccessors(vd) ::: beanAccessors(vd) - } - // Take into account annotations so that we keep annotated unit lazy val - // to get better error message already from the cps plugin itself - def hasUnitType(sym: Symbol) = (sym.tpe.typeSymbol == UnitClass) && sym.tpe.annotations.isEmpty + def field(vd: ValDef): List[Field] = if (Field.noFieldFor(vd)) Nil else List(Field(vd)) /** This trait assembles what's needed for synthesizing derived methods. * Important: Typically, instances of this trait are created TWICE for each derived @@ -260,7 +256,6 @@ trait MethodSynthesis { def name: TermName /** The flags that are retained from the original symbol */ - def flagsMask: Long /** The flags that the derived symbol has in addition to those retained from @@ -284,8 +279,9 @@ trait MethodSynthesis { def enclClass: Symbol // Final methods to make the rest easier to reason about. - final def mods = tree.mods - final def basisSym = tree.symbol + final def mods = tree.mods + final def basisSym = tree.symbol + final def derivedMods = mods & flagsMask | flagsExtra } sealed trait DerivedFromClassDef extends DerivedFromMemberDef { @@ -305,7 +301,6 @@ trait MethodSynthesis { /* Explicit isSetter required for bean setters (beanSetterSym.isSetter is false) */ final def completer(sym: Symbol) = namerOf(sym).accessorTypeCompleter(tree, isSetter) final def fieldSelection = Select(This(enclClass), basisSym) - final def derivedMods: Modifiers = mods & flagsMask | flagsExtra mapAnnotations (_ => Nil) def derivedSym: Symbol = tree.symbol def derivedTree: Tree = EmptyTree @@ -314,8 +309,8 @@ trait MethodSynthesis { def isDeferred = mods.isDeferred def keepClean = false // whether annotations whose definitions are not meta-annotated should be kept. def validate() { } - def createAndEnterSymbol(): Symbol = { - val sym = owner.newMethod(name, tree.pos.focus, (tree.mods.flags & flagsMask) | flagsExtra) + def createAndEnterSymbol(): MethodSymbol = { + val sym = owner.newMethod(name, tree.pos.focus, derivedMods.flags) setPrivateWithin(tree, sym) enterInScope(sym) sym setInfo completer(sym) @@ -333,7 +328,8 @@ trait MethodSynthesis { } } sealed trait DerivedGetter extends DerivedFromValDef { - // TODO + // A getter must be accompanied by a setter if the ValDef is mutable. + def needsSetter = mods.isMutable } sealed trait DerivedSetter extends DerivedFromValDef { override def isSetter = true @@ -341,10 +337,13 @@ trait MethodSynthesis { case (p :: Nil) :: _ => p case _ => NoSymbol } - private def setterRhs = ( - if (mods.isDeferred || derivedSym.isOverloaded) EmptyTree + + private def setterRhs = { + assert(!derivedSym.isOverloaded, s"Unexpected overloaded setter $derivedSym for $basisSym in $enclClass") + if (Field.noFieldFor(tree) || derivedSym.isOverloaded) EmptyTree else Assign(fieldSelection, Ident(setterParam)) - ) + } + private def setterDef = DefDef(derivedSym, setterRhs) override def derivedTree: Tree = if (setterParam == NoSymbol) EmptyTree else setterDef } @@ -363,8 +362,7 @@ trait MethodSynthesis { context.error(tree.pos, s"Internal error: Unable to find the synthetic factory method corresponding to implicit class $name in $enclClass / ${enclClass.info.decls}") result } - def derivedTree: DefDef = - factoryMeth(mods & flagsMask | flagsExtra, name, tree) + def derivedTree: DefDef = factoryMeth(derivedMods, name, tree) def flagsExtra: Long = METHOD | IMPLICIT | SYNTHETIC def flagsMask: Long = AccessFlags def name: TermName = tree.name.toTermName @@ -385,8 +383,9 @@ trait MethodSynthesis { } } case class Getter(tree: ValDef) extends BaseGetter(tree) { - override def derivedSym = if (mods.isDeferred) basisSym else basisSym.getterIn(enclClass) - private def derivedRhs = if (mods.isDeferred) EmptyTree else fieldSelection + override def derivedSym = if (Field.noFieldFor(tree)) basisSym else basisSym.getterIn(enclClass) + private def derivedRhs = if (Field.noFieldFor(tree)) tree.rhs else fieldSelection + private def derivedTpt = { // For existentials, don't specify a type for the getter, even one derived // from the symbol! This leads to incompatible existentials for the field and @@ -400,19 +399,21 @@ trait MethodSynthesis { // Range position errors ensue if we don't duplicate this in some // circumstances (at least: concrete vals with existential types.) case ExistentialType(_, _) => TypeTree() setOriginal (tree.tpt.duplicate setPos tree.tpt.pos.focus) - case _ if mods.isDeferred => TypeTree() setOriginal tree.tpt // keep type tree of original abstract field + case _ if isDeferred => TypeTree() setOriginal tree.tpt // keep type tree of original abstract field case tp => TypeTree(tp) } tpt setPos tree.tpt.pos.focus } override def derivedTree: DefDef = newDefDef(derivedSym, derivedRhs)(tpt = derivedTpt) } + /** Implements lazy value accessors: - * - for lazy values of type Unit and all lazy fields inside traits, - * the rhs is the initializer itself - * - for all other lazy values z the accessor is a block of this form: - * { z = <rhs>; z } where z can be an identifier or a field. - */ + * - for lazy values of type Unit and all lazy fields inside traits, + * the rhs is the initializer itself, because we'll just "compute" the result on every access + * ("computing" unit / constant type is free -- the side-effect is still only run once, using the init bitmap) + * - for all other lazy values z the accessor is a block of this form: + * { z = <rhs>; z } where z can be an identifier or a field. + */ case class LazyValGetter(tree: ValDef) extends BaseGetter(tree) { class ChangeOwnerAndModuleClassTraverser(oldowner: Symbol, newowner: Symbol) extends ChangeOwnerTraverser(oldowner, newowner) { @@ -432,10 +433,10 @@ trait MethodSynthesis { override def derivedTree: DefDef = { val ValDef(_, _, tpt0, rhs0) = tree val rhs1 = context.unit.transformed.getOrElse(rhs0, rhs0) - val body = ( - if (tree.symbol.owner.isTrait || hasUnitType(basisSym)) rhs1 + val body = + if (tree.symbol.owner.isTrait || Field.noFieldFor(tree)) rhs1 // TODO move tree.symbol.owner.isTrait into noFieldFor else gen.mkAssignAndReturn(basisSym, rhs1) - ) + derivedSym setPos tree.pos // cannot set it at createAndEnterSymbol because basisSym can possibly still have NoPosition val ddefRes = DefDef(derivedSym, new ChangeOwnerAndModuleClassTraverser(basisSym, derivedSym)(body)) // ValDef will have its position focused whereas DefDef will have original correct rangepos @@ -454,6 +455,24 @@ trait MethodSynthesis { override def derivedSym = basisSym.setterIn(enclClass) } + + object Field { + // No field for these vals (either never emitted or eliminated later on): + // - abstract vals have no value we could store (until they become concrete, potentially) + // - lazy vals of type Unit + // - [Emitted, later removed during AddInterfaces/Mixins] concrete vals in traits can't have a field + // - [Emitted, later removed during Constructors] a concrete val with a statically known value (Unit / ConstantType) + // performs its side effect according to lazy/strict semantics, but doesn't need to store its value + // each access will "evaluate" the RHS (a literal) again + // We would like to avoid emitting unnecessary fields, but the required knowledge isn't available until after typer. + // The only way to avoid emitting & suppressing, is to not emit at all until we are sure to need the field, as dotty does. + // NOTE: do not look at `vd.symbol` when called from `enterGetterSetter` (luckily, that call-site implies `!mods.isLazy`), + // as the symbol info is in the process of being created then. + // TODO: harmonize tree & symbol creation + // TODO: the `def field` call-site does not tollerate including `|| vd.symbol.owner.isTrait` --> tests break + def noFieldFor(vd: ValDef) = vd.mods.isDeferred || (vd.mods.isLazy && isUnitType(vd.symbol.info)) // || vd.symbol.owner.isTrait)) + } + case class Field(tree: ValDef) extends DerivedFromValDef { def name = tree.localName def category = FieldTargetClass @@ -462,11 +481,13 @@ trait MethodSynthesis { // By default annotations go to the field, except if the field is // generated for a class parameter (PARAMACCESSOR). override def keepClean = !mods.isParamAccessor - override def derivedTree = ( - if (mods.isDeferred) EmptyTree - else if (mods.isLazy) copyValDef(tree)(mods = mods | flagsExtra, name = this.name, rhs = EmptyTree).setPos(tree.pos.focus) + + // handle lazy val first for now (we emit a Field even though we probably shouldn't...) + override def derivedTree = + if (mods.isLazy) copyValDef(tree)(mods = mods | flagsExtra, name = this.name, rhs = EmptyTree).setPos(tree.pos.focus) + else if (Field.noFieldFor(tree)) EmptyTree else copyValDef(tree)(mods = mods | flagsExtra, name = this.name) - ) + } case class Param(tree: ValDef) extends DerivedFromValDef { def name = tree.name @@ -501,12 +522,12 @@ trait MethodSynthesis { // Derives a tree without attempting to use the original tree's symbol. override def derivedTree = { atPos(tree.pos.focus) { - DefDef(derivedMods, name, Nil, ListOfNil, tree.tpt.duplicate, + DefDef(derivedMods mapAnnotations (_ => Nil), name, Nil, ListOfNil, tree.tpt.duplicate, if (isDeferred) EmptyTree else Select(This(owner), tree.name) ) } } - override def createAndEnterSymbol(): Symbol = enterSyntheticSym(derivedTree) + override def createAndEnterSymbol(): MethodSymbol = enterSyntheticSym(derivedTree).asInstanceOf[MethodSymbol] } case class BooleanBeanGetter(tree: ValDef) extends BeanAccessor("is") with AnyBeanGetter { } case class BeanGetter(tree: ValDef) extends BeanAccessor("get") with AnyBeanGetter { } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 4ad81b60ae..254cb7111c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -115,21 +115,14 @@ trait Namers extends MethodSynthesis { TypeSigError(tree, ex) alt } - // PRIVATE | LOCAL are fields generated for primary constructor arguments - // @PP: ...or fields declared as private[this]. PARAMACCESSOR marks constructor arguments. - // Neither gets accessors so the code is as far as I know still correct. - def noEnterGetterSetter(vd: ValDef) = !vd.mods.isLazy && ( - !owner.isClass - || (vd.mods.isPrivateLocal && !vd.mods.isCaseAccessor) - || (vd.name startsWith nme.OUTER) - || (context.unit.isJava) - || isEnumConstant(vd) - ) - def noFinishGetterSetter(vd: ValDef) = ( - (vd.mods.isPrivateLocal && !vd.mods.isLazy) // all lazy vals need accessors, even private[this] - || vd.symbol.isModuleVar - || isEnumConstant(vd)) + // All lazy vals need accessors, including those owned by terms (e.g., in method) or private[this] in a class + def deriveAccessors(vd: ValDef) = vd.mods.isLazy || (owner.isClass && deriveAccessorsInClass(vd)) + + private def deriveAccessorsInClass(vd: ValDef) = + !vd.mods.isPrivateLocal && // note, private[this] lazy vals do get accessors -- see outer disjunction of deriveAccessors + !(vd.name startsWith nme.OUTER) && // outer accessors are added later, in explicitouter + !isEnumConstant(vd) // enums can only occur in classes, so only check here /** Determines whether this field holds an enum constant. * To qualify, the following conditions must be met: @@ -655,11 +648,15 @@ trait Namers extends MethodSynthesis { } } - def enterValDef(tree: ValDef) { - if (noEnterGetterSetter(tree)) - assignAndEnterFinishedSymbol(tree) - else - enterGetterSetter(tree) + def enterValDef(tree: ValDef): Unit = { + val isScala = !context.unit.isJava + if (isScala) { + if (nme.isSetterName(tree.name)) ValOrVarWithSetterSuffixError(tree) + if (tree.mods.isPrivateLocal && tree.mods.isCaseAccessor) PrivateThisCaseClassParameterError(tree) + } + + if (isScala && deriveAccessors(tree)) enterGetterSetter(tree) + else assignAndEnterFinishedSymbol(tree) if (isEnumConstant(tree)) tree.symbol setInfo ConstantType(Constant(tree.symbol)) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 0198529ef7..7252cae0b5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1188,20 +1188,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // set NoType so it will be ignored. val cdef = ClassDef(module.moduleClass, impl) setType NoType - // Create the module var unless the immediate owner is a class and - // the module var already exists there. See SI-5012, SI-6712. - def findOrCreateModuleVar() = { - val vsym = ( - if (site.isTerm) NoSymbol - else site.info decl nme.moduleVarName(moduleName) - ) - vsym orElse (site newModuleVarSymbol module) - } def newInnerObject() = { - // Create the module var unless it is already in the module owner's scope. - // The lookup is on module.enclClass and not module.owner lest there be a - // nullary method between us and the class; see SI-5012. - val moduleVar = findOrCreateModuleVar() + val moduleVar = site newModuleVarSymbol module val rhs = gen.newModule(module, moduleVar.tpe) val body = if (site.isTrait) rhs else gen.mkAssignAndReturn(moduleVar, rhs) val accessor = DefDef(module, body.changeOwner(moduleVar -> module)) @@ -1217,6 +1205,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } val newTrees = cdef :: ( if (module.isStatic) + // trait T { def f: Object }; object O extends T { object f }. Need to generate method f in O. if (module.isOverridingSymbol) matchingInnerObject() else Nil else newInnerObject() @@ -1468,10 +1457,13 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case m: MemberDef => val sym = m.symbol applyChecks(sym.annotations) - // validate implicitNotFoundMessage - analyzer.ImplicitNotFoundMsg.check(sym) foreach { warn => - reporter.warning(tree.pos, f"Invalid implicitNotFound message for ${sym}%s${sym.locationString}%s:%n$warn") - } + + def messageWarning(name: String)(warn: String) = + reporter.warning(tree.pos, f"Invalid $name message for ${sym}%s${sym.locationString}%s:%n$warn") + + // validate implicitNotFoundMessage and implicitAmbiguousMessage + analyzer.ImplicitNotFoundMsg.check(sym) foreach messageWarning("implicitNotFound") + analyzer.ImplicitAmbiguousMsg.check(sym) foreach messageWarning("implicitAmbiguous") case tpt@TypeTree() => if(tpt.original != null) { @@ -1511,7 +1503,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans sym.isSourceMethod && sym.isCase && sym.name == nme.apply && - isClassTypeAccessible(tree) + isClassTypeAccessible(tree) && + !tree.tpe.resultType.typeSymbol.primaryConstructor.isLessAccessibleThan(tree.symbol) if (doTransform) { tree foreach { diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala index ea44b9dc39..92b0719ba3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala +++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala @@ -132,7 +132,7 @@ trait StdAttachments { /** Marks the tree as a macro impl reference, which is a naked reference to a method. * * This is necessary for typechecking macro impl references (see `DefaultMacroCompiler.defaultResolveMacroImpl`), - * because otherwise typing a naked reference will result in the "follow this method with `_' if you want to + * because otherwise typing a naked reference will result in the "follow this method with `_` if you want to * treat it as a partially applied function" errors. * * This mark suppresses adapt except for when the annottee is a macro application. diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index d65d2092ad..4ccc183334 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -304,6 +304,7 @@ trait SyntheticMethods extends ast.TreeDSL { clazz.isModuleClass && clazz.isSerializable && !hasConcreteImpl(nme.readResolve) + && clazz.isStatic ) def synthesize(): List[Tree] = { @@ -335,16 +336,18 @@ trait SyntheticMethods extends ast.TreeDSL { } for ((m, impl) <- methods ; if shouldGenerate(m)) yield impl() } - def extras = ( + def extras = { if (needsReadResolve) { // Aha, I finally decoded the original comment. // This method should be generated as private, but apparently if it is, then // it is name mangled afterward. (Wonder why that is.) So it's only protected. // For sure special methods like "readResolve" should not be mangled. - List(createMethod(nme.readResolve, Nil, ObjectTpe)(m => { m setFlag PRIVATE ; REF(clazz.sourceModule) })) + List(createMethod(nme.readResolve, Nil, ObjectTpe)(m => { + m setFlag PRIVATE; REF(clazz.sourceModule) + })) } else Nil - ) + } try impls ++ extras catch { case _: TypeError if reporter.hasErrors => Nil } diff --git a/src/compiler/scala/tools/nsc/typechecker/Tags.scala b/src/compiler/scala/tools/nsc/typechecker/Tags.scala index 57dc74d2a0..56127f4026 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Tags.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Tags.scala @@ -36,7 +36,7 @@ trait Tags { * @param allowMaterialization If true (default) then the resolver is allowed to launch materialization macros when there's no class tag in scope. * If false then materialization macros are prohibited from running. * - * @returns Tree that represents an `scala.reflect.ClassTag` for `tp` if everything is okay. + * @return Tree that represents an `scala.reflect.ClassTag` for `tp` if everything is okay. * EmptyTree if the result contains unresolved (i.e. not spliced) type parameters and abstract type members. * EmptyTree if `allowMaterialization` is false, and there is no class tag in scope. */ @@ -57,7 +57,7 @@ trait Tags { * @param allowMaterialization If true (default) then the resolver is allowed to launch materialization macros when there's no type tag in scope. * If false then materialization macros are prohibited from running. * - * @returns Tree that represents a `scala.reflect.TypeTag` for `tp` if everything is okay. + * @return Tree that represents a `scala.reflect.TypeTag` for `tp` if everything is okay. * EmptyTree if `concrete` is true and the result contains unresolved (i.e. not spliced) type parameters and abstract type members. * EmptyTree if `allowMaterialization` is false, and there is no array tag in scope. */ diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index a7d48ceb89..e8db8309f1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -262,7 +262,14 @@ abstract class TreeCheckers extends Analyzer { checkedTyped(tree, mode, pt) ) private def checkedTyped(tree: Tree, mode: Mode, pt: Type): Tree = { - val typed = wrap(tree)(super.typed(tree, mode, pt)) + val typed = wrap(tree)(super.typed(tree.clearType(), mode, pt)) + + // Vlad: super.typed returns null for package defs, why is that? + if (typed eq null) + return tree + + if (typed.tpe ne null) + assert(!typed.tpe.isErroneous, "Tree has erroneous type: " + typed) if (tree ne typed) treesDiffer(tree, typed) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index cc15a2485f..f26baf7d93 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2714,7 +2714,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper * * If 'T' is not fully defined, it is inferred by type checking * `apply$body` without a result type before type checking the block. - * The method's inferred result type is used instead of T`. [See test/files/pos/sammy_poly.scala] + * The method's inferred result type is used instead of `T`. [See test/files/pos/sammy_poly.scala] * * The `apply` method is identified by the argument `sam`; `S` corresponds to the argument `samClassTp`, * and `resPt` is derived from `samClassTp` -- it may be fully defined, or not... @@ -3294,7 +3294,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.3 // // One can think of these methods as being infinitely overloaded. We create - // a ficticious new cloned method symbol for each call site that takes on a signature + // a fictitious new cloned method symbol for each call site that takes on a signature // governed by a) the argument types and b) the expected type val args1 = typedArgs(args, forArgMode(fun, mode)) val pts = args1.map(_.tpe.deconst) @@ -4095,7 +4095,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def resultingTypeTree(tpe: Type) = { // we need symbol-ful originals for reification - // hence we go the extra mile to hand-craft tis guy + // hence we go the extra mile to hand-craft this guy val original = arg1 match { case tt @ TypeTree() if tt.original != null => Annotated(ann, tt.original) // this clause is needed to correctly compile stuff like "new C @D" or "@(inline @getter)" @@ -4247,7 +4247,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // in the special (though common) case where the types are equal, it pays to pack before comparing // especially virtpatmat needs more aggressive unification of skolemized types // this breaks src/library/scala/collection/immutable/TrieIterator.scala - // annotated types need to be lubbed regardless (at least, continations break if you by pass them like this) + // annotated types need to be lubbed regardless (at least, continuations break if you bypass them like this) def samePackedTypes = ( !isPastTyper && thenp1.tpe.annotations.isEmpty diff --git a/src/compiler/scala/tools/nsc/typechecker/TypersTracking.scala b/src/compiler/scala/tools/nsc/typechecker/TypersTracking.scala index 550fd4e68d..37fbb73b85 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypersTracking.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypersTracking.scala @@ -159,7 +159,7 @@ trait TypersTracking { // Some trees which are typed with mind-numbing frequency and // which add nothing by being printed. Did () type to Unit? Let's // gamble on yes. - private def printingOk(t: Tree) = printTypings && (settings.debug.value || !noPrint(t)) + def printingOk(t: Tree) = printTypings && (settings.debug.value || !noPrint(t)) def noPrintTyping(t: Tree) = (t.tpe ne null) || !printingOk(t) def noPrintAdapt(tree1: Tree, tree2: Tree) = !printingOk(tree1) || ( (tree1.tpe == tree2.tpe) diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 8d4d07759f..2811520b67 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -22,7 +22,7 @@ import Jar.isJarOrZip /** <p> * This module provides star expansion of '-classpath' option arguments, behaves the same as - * java, see [http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html] + * java, see [[http://docs.oracle.com/javase/6/docs/technotes/tools/windows/classpath.html]] * </p> * * @author Stepan Koltsov diff --git a/src/compiler/scala/tools/nsc/util/DocStrings.scala b/src/compiler/scala/tools/nsc/util/DocStrings.scala index 4ff7067a21..501546b8f6 100755 --- a/src/compiler/scala/tools/nsc/util/DocStrings.scala +++ b/src/compiler/scala/tools/nsc/util/DocStrings.scala @@ -37,7 +37,7 @@ object DocStrings { /** Returns index of string `str` after `start` skipping longest * sequence of space and tab characters, possibly also containing * a single `*` character or the `/``**` sequence. - * @pre start == str.length || str(start) == `\n' + * @pre start == str.length || str(start) == `\n` */ def skipLineLead(str: String, start: Int): Int = if (start == str.length) start @@ -49,7 +49,7 @@ object DocStrings { else idx } - /** Skips to next occurrence of `\n' or to the position after the `/``**` sequence following index `start`. + /** Skips to next occurrence of `\n` or to the position after the `/``**` sequence following index `start`. */ def skipToEol(str: String, start: Int): Int = if (start + 2 < str.length && (str charAt start) == '/' && (str charAt (start + 1)) == '*' && (str charAt (start + 2)) == '*') start + 3 diff --git a/src/compiler/scala/tools/reflect/ReflectGlobal.scala b/src/compiler/scala/tools/reflect/ReflectGlobal.scala index ac63232967..e30d1ed7cd 100644 --- a/src/compiler/scala/tools/reflect/ReflectGlobal.scala +++ b/src/compiler/scala/tools/reflect/ReflectGlobal.scala @@ -1,9 +1,11 @@ package scala.tools package reflect +import scala.reflect.internal.util.ScalaClassLoader import scala.tools.nsc.Global import scala.tools.nsc.reporters.Reporter import scala.tools.nsc.Settings +import scala.tools.nsc.typechecker.Analyzer /** A version of Global that uses reflection to get class * infos, instead of reading class or source files. @@ -11,6 +13,20 @@ import scala.tools.nsc.Settings class ReflectGlobal(currentSettings: Settings, reporter: Reporter, override val rootClassLoader: ClassLoader) extends Global(currentSettings, reporter) with scala.tools.reflect.ReflectSetup with scala.reflect.runtime.SymbolTable { + override lazy val analyzer = new { + val global: ReflectGlobal.this.type = ReflectGlobal.this + } with Analyzer { + /** Obtains the classLoader used for runtime macro expansion. + * + * Macro expansion can use everything available in [[global.classPath]] or [[rootClassLoader]]. + * The [[rootClassLoader]] is used to obtain runtime defined macros. + */ + override protected def findMacroClassLoader(): ClassLoader = { + val classpath = global.classPath.asURLs + ScalaClassLoader.fromURLs(classpath, rootClassLoader) + } + } + override def transformedType(sym: Symbol) = postErasure.transformInfo(sym, erasure.transformInfo(sym, diff --git a/src/library-aux/scala/Any.scala b/src/library-aux/scala/Any.scala index 1be186d114..8caf0c5c0e 100644 --- a/src/library-aux/scala/Any.scala +++ b/src/library-aux/scala/Any.scala @@ -27,7 +27,7 @@ package scala * w.print() * }}} * - * See the [[http://docs.scala-lang.org/sips/pending/value-classes.html value classes guide]] for more + * See the [[http://docs.scala-lang.org/sips/completed/value-classes.html value classes guide]] for more * details on the interplay of universal traits and value classes. */ abstract class Any { diff --git a/src/library/scala/AnyVal.scala b/src/library/scala/AnyVal.scala index ff62948413..fb3d213e19 100644 --- a/src/library/scala/AnyVal.scala +++ b/src/library/scala/AnyVal.scala @@ -49,7 +49,7 @@ package scala * It's important to note that user-defined value classes are limited, and in some circumstances, * still must allocate a value class instance at runtime. These limitations and circumstances are * explained in greater detail in the [[http://docs.scala-lang.org/overviews/core/value-classes.html Value Classes Guide]] - * as well as in [[http://docs.scala-lang.org/sips/pending/value-classes.html SIP-15: Value Classes]], + * as well as in [[http://docs.scala-lang.org/sips/completed/value-classes.html SIP-15: Value Classes]], * the Scala Improvement Proposal. */ abstract class AnyVal extends Any { diff --git a/src/library/scala/Equals.scala b/src/library/scala/Equals.scala index f2f9ead44c..e06557ccdd 100644 --- a/src/library/scala/Equals.scala +++ b/src/library/scala/Equals.scala @@ -13,8 +13,9 @@ package scala */ trait Equals extends Any { /** A method that should be called from every well-designed equals method - * that is open to be overridden in a subclass. See Programming in Scala, - * Chapter 28 for discussion and design. + * that is open to be overridden in a subclass. See + * [[http://www.artima.com/pins1ed/object-equality.html Programming in Scala, + * Chapter 28]] for discussion and design. * * @param that the value being probed for possible equality * @return true if this instance can possibly equal `that`, otherwise false diff --git a/src/library/scala/Option.scala b/src/library/scala/Option.scala index f134f5ce3d..7282feebb6 100644 --- a/src/library/scala/Option.scala +++ b/src/library/scala/Option.scala @@ -270,7 +270,7 @@ sealed abstract class Option[+A] extends Product with Serializable { * // Returns None because the partial function doesn't cover the case. * Some("ftp") collect {case "http" => "HTTP"} * - * // Returns None because None is passed to the collect method. + * // Returns None because the option is empty. There is no value to pass to the partial function. * None collect {case value => value} * }}} * diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index fa58015a84..334377e838 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -56,7 +56,7 @@ import scala.io.StdIn * only contain natural numbers (i.e. non-negative), and that the result returned * will also be natural. `require` is distinct from `assert` in that if the * condition fails, then the caller of the function is to blame rather than a - * logical error having been made within `addNaturals` itself. `ensures` is a + * logical error having been made within `addNaturals` itself. `ensuring` is a * form of `assert` that declares the guarantee the function is providing with * regards to its return value. * diff --git a/src/library/scala/annotation/implicitAmbiguous.scala b/src/library/scala/annotation/implicitAmbiguous.scala new file mode 100644 index 0000000000..46eab9ae8f --- /dev/null +++ b/src/library/scala/annotation/implicitAmbiguous.scala @@ -0,0 +1,34 @@ +package scala.annotation + +import scala.annotation.meta._ + +/** + * To customize the error message that's emitted when an implicit of type + * C[T1,..., TN] is found more than once, annotate the class C + * with @implicitAmbiguous. Assuming C has type parameters X1,..., XN, the + * error message will be the result of replacing all occurrences of ${Xi} in + * the string msg with the string representation of the corresponding type + * argument Ti. * + * + * If more than one @implicitAmbiguous annotation is collected, the compiler is + * free to pick any of them to display. + * + * Nice errors can direct users to fix imports or even tell them why code + * intentionally doesn't compile. + * + * {{{ + * trait =!=[C, D] + * + * implicit def neq[E, F] : E =!= F = null + * + * @annotation.implicitAmbiguous("Could not prove ${J} =!= ${J}") + * implicit def neqAmbig1[G, H, J] : J =!= J = null + * implicit def neqAmbig2[I] : I =!= I = null + * + * implicitly[Int =!= Int] + * }}} + * + * @author Brian McKenna + * @since 2.12.0 + */ +final class implicitAmbiguous(msg: String) extends scala.annotation.StaticAnnotation {} diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index 49b4397cf2..603d97c3ad 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -162,13 +162,6 @@ class HashSet[A] extends AbstractSet[A] def - (e: A): HashSet[A] = nullToEmpty(removed0(e, computeHash(e), 0)) - /** Returns this $coll as an immutable set. - * - * A new set will not be built; lazy collections will stay lazy. - */ - @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0") - override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]] - override def filter(p: A => Boolean) = { val buffer = new Array[HashSet[A]](bufferSize(size)) nullToEmpty(filter0(p, false, 0, buffer, 0)) @@ -201,6 +194,7 @@ class HashSet[A] extends AbstractSet[A] protected def writeReplace(): AnyRef = new HashSet.SerializationProxy(this) + override def toSet[B >: A]: Set[B] = this.asInstanceOf[HashSet[B]] } /** $factoryInfo diff --git a/src/library/scala/collection/immutable/ListSet.scala b/src/library/scala/collection/immutable/ListSet.scala index a6e6fba0a5..adc975479a 100644 --- a/src/library/scala/collection/immutable/ListSet.scala +++ b/src/library/scala/collection/immutable/ListSet.scala @@ -138,13 +138,6 @@ class ListSet[A] extends AbstractSet[A] override def stringPrefix = "ListSet" - /** Returns this $coll as an immutable set. - * - * A new set will not be built; lazy collections will stay lazy. - */ - @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0") - override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]] - /** Represents an entry in the `ListSet`. */ protected class Node(override val head: A) extends ListSet[A] with Serializable { @@ -186,4 +179,6 @@ class ListSet[A] extends AbstractSet[A] override def tail: ListSet[A] = self } + + override def toSet[B >: A]: Set[B] = this.asInstanceOf[ListSet[B]] } diff --git a/src/library/scala/collection/immutable/MapLike.scala b/src/library/scala/collection/immutable/MapLike.scala index 94a5b7929a..bd5b9c9faf 100644 --- a/src/library/scala/collection/immutable/MapLike.scala +++ b/src/library/scala/collection/immutable/MapLike.scala @@ -113,6 +113,11 @@ self => override def - (elem: A): immutable.Set[A] = if (this(elem)) immutable.Set[A]() ++ this - elem else this + + // ImmutableDefaultKeySet is only protected, so we won't warn on override. + // Someone could override in a way that makes widening not okay + // (e.g. by overriding +, though the version in this class is fine) + override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]] } /** This function transforms all the values of mappings contained diff --git a/src/library/scala/collection/immutable/Set.scala b/src/library/scala/collection/immutable/Set.scala index 7725ad9ee3..a115469b83 100644 --- a/src/library/scala/collection/immutable/Set.scala +++ b/src/library/scala/collection/immutable/Set.scala @@ -35,7 +35,22 @@ trait Set[A] extends Iterable[A] override def companion: GenericCompanion[Set] = Set - override def toSet[B >: A]: Set[B] = to[({type l[a] = immutable.Set[B]})#l] // for bincompat; remove in dev + /** Returns this $coll as an immutable set, perhaps accepting a + * wider range of elements. Since it already is an + * immutable set, it will only be rebuilt if the underlying structure + * cannot be expanded to include arbitrary element types. + * For instance, `BitSet` and `SortedSet` will be rebuilt, as + * they require `Int` and sortable elements respectively. + * + * When in doubt, the set will be rebuilt. Rebuilt sets never + * need to be rebuilt again. + */ + override def toSet[B >: A]: Set[B] = { + // This way of building sets typically has the best benchmarks, surprisingly! + val sb = Set.newBuilder[B] + foreach(sb += _) + sb.result() + } override def seq: Set[A] = this protected override def parCombiner = ParSet.newCombiner[A] // if `immutable.SetLike` gets introduced, please move this there! @@ -88,8 +103,10 @@ object Set extends ImmutableSetFactory[Set] { if (f(elem1)) Some(elem1) else None } - @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0") - override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]] + // Why is Set1 non-final? Need to fix that! + @deprecatedOverriding("This immutable set should do nothing on toSet but cast itself to a Set with a wider element type.", "2.11.8") + override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set1[B]] + } /** An optimized representation for immutable sets of size 2 */ @@ -121,8 +138,9 @@ object Set extends ImmutableSetFactory[Set] { else if (f(elem2)) Some(elem2) else None } - @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0") - override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]] + // Why is Set2 non-final? Need to fix that! + @deprecatedOverriding("This immutable set should do nothing on toSet but cast itself to a Set with a wider element type.", "2.11.8") + override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set2[B]] } /** An optimized representation for immutable sets of size 3 */ @@ -156,8 +174,9 @@ object Set extends ImmutableSetFactory[Set] { else if (f(elem3)) Some(elem3) else None } - @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0") - override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]] + // Why is Set3 non-final? Need to fix that! + @deprecatedOverriding("This immutable set should do nothing on toSet but cast itself to a Set with a wider element type.", "2.11.8") + override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set3[B]] } /** An optimized representation for immutable sets of size 4 */ @@ -193,8 +212,9 @@ object Set extends ImmutableSetFactory[Set] { else if (f(elem4)) Some(elem4) else None } - @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0") - override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]] + // Why is Set4 non-final? Need to fix that! + @deprecatedOverriding("This immutable set should do nothing on toSet but cast itself to a Set with a wider element type.", "2.11.8") + override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set4[B]] } } diff --git a/src/library/scala/collection/immutable/SortedMap.scala b/src/library/scala/collection/immutable/SortedMap.scala index f1493551ab..682788e18e 100644 --- a/src/library/scala/collection/immutable/SortedMap.scala +++ b/src/library/scala/collection/immutable/SortedMap.scala @@ -53,6 +53,12 @@ self => val map = self.rangeImpl(from, until) new map.DefaultKeySortedSet } + override def toSet[C >: A]: Set[C] = { + // This way of building sets typically has the best benchmarks, surprisingly! + val sb = Set.newBuilder[C] + foreach(sb += _) + sb.result() + } } /** Add a key/value pair to this map. diff --git a/src/library/scala/collection/mutable/AVLTree.scala b/src/library/scala/collection/mutable/AVLTree.scala deleted file mode 100644 index b63d0aae33..0000000000 --- a/src/library/scala/collection/mutable/AVLTree.scala +++ /dev/null @@ -1,250 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala -package collection -package mutable - -/** - * An immutable AVL Tree implementation formerly used by mutable.TreeSet - * - * @author Lucien Pereira - */ -@deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.2") -private[mutable] sealed trait AVLTree[+A] extends Serializable { - def balance: Int - - def depth: Int - - def iterator[B >: A]: Iterator[B] = Iterator.empty - - def contains[B >: A](value: B, ordering: Ordering[B]): Boolean = false - - /** - * Returns a new tree containing the given element. - * Throws an IllegalArgumentException if element is already present. - * - */ - def insert[B >: A](value: B, ordering: Ordering[B]): AVLTree[B] = Node(value, Leaf, Leaf) - - /** - * Return a new tree which not contains given element. - * - */ - def remove[B >: A](value: B, ordering: Ordering[B]): AVLTree[A] = - throw new NoSuchElementException(String.valueOf(value)) - - /** - * Return a tuple containing the smallest element of the provided tree - * and a new tree from which this element has been extracted. - * - */ - def removeMin[B >: A]: (B, AVLTree[B]) = sys.error("Should not happen.") - - /** - * Return a tuple containing the biggest element of the provided tree - * and a new tree from which this element has been extracted. - * - */ - def removeMax[B >: A]: (B, AVLTree[B]) = sys.error("Should not happen.") - - def rebalance[B >: A]: AVLTree[B] = this - - def leftRotation[B >: A]: Node[B] = sys.error("Should not happen.") - - def rightRotation[B >: A]: Node[B] = sys.error("Should not happen.") - - def doubleLeftRotation[B >: A]: Node[B] = sys.error("Should not happen.") - - def doubleRightRotation[B >: A]: Node[B] = sys.error("Should not happen.") -} - -/** - * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0") - */ -private case object Leaf extends AVLTree[Nothing] { - override val balance: Int = 0 - - override val depth: Int = -1 -} - -/** - * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0") - */ -private case class Node[A](data: A, left: AVLTree[A], right: AVLTree[A]) extends AVLTree[A] { - override val balance: Int = right.depth - left.depth - - override val depth: Int = math.max(left.depth, right.depth) + 1 - - override def iterator[B >: A]: Iterator[B] = new AVLIterator(this) - - override def contains[B >: A](value: B, ordering: Ordering[B]) = { - val ord = ordering.compare(value, data) - if (0 == ord) - true - else if (ord < 0) - left.contains(value, ordering) - else - right.contains(value, ordering) - } - - /** - * Returns a new tree containing the given element. - * Throws an IllegalArgumentException if element is already present. - * - */ - override def insert[B >: A](value: B, ordering: Ordering[B]) = { - val ord = ordering.compare(value, data) - if (0 == ord) - throw new IllegalArgumentException() - else if (ord < 0) - Node(data, left.insert(value, ordering), right).rebalance - else - Node(data, left, right.insert(value, ordering)).rebalance - } - - /** - * Return a new tree which not contains given element. - * - */ - override def remove[B >: A](value: B, ordering: Ordering[B]): AVLTree[A] = { - val ord = ordering.compare(value, data) - if(ord == 0) { - if (Leaf == left) { - if (Leaf == right) { - Leaf - } else { - val (min, newRight) = right.removeMin - Node(min, left, newRight).rebalance - } - } else { - val (max, newLeft) = left.removeMax - Node(max, newLeft, right).rebalance - } - } else if (ord < 0) { - Node(data, left.remove(value, ordering), right).rebalance - } else { - Node(data, left, right.remove(value, ordering)).rebalance - } - } - - /** - * Return a tuple containing the smallest element of the provided tree - * and a new tree from which this element has been extracted. - * - */ - override def removeMin[B >: A]: (B, AVLTree[B]) = { - if (Leaf == left) - (data, right) - else { - val (min, newLeft) = left.removeMin - (min, Node(data, newLeft, right).rebalance) - } - } - - /** - * Return a tuple containing the biggest element of the provided tree - * and a new tree from which this element has been extracted. - * - */ - override def removeMax[B >: A]: (B, AVLTree[B]) = { - if (Leaf == right) - (data, left) - else { - val (max, newRight) = right.removeMax - (max, Node(data, left, newRight).rebalance) - } - } - - override def rebalance[B >: A] = { - if (-2 == balance) { - if (1 == left.balance) - doubleRightRotation - else - rightRotation - } else if (2 == balance) { - if (-1 == right.balance) - doubleLeftRotation - else - leftRotation - } else { - this - } - } - - override def leftRotation[B >: A] = { - if (Leaf != right) { - val r: Node[A] = right.asInstanceOf[Node[A]] - Node(r.data, Node(data, left, r.left), r.right) - } else sys.error("Should not happen.") - } - - override def rightRotation[B >: A] = { - if (Leaf != left) { - val l: Node[A] = left.asInstanceOf[Node[A]] - Node(l.data, l.left, Node(data, l.right, right)) - } else sys.error("Should not happen.") - } - - override def doubleLeftRotation[B >: A] = { - if (Leaf != right) { - val r: Node[A] = right.asInstanceOf[Node[A]] - // Let's save an instanceOf by 'inlining' the left rotation - val rightRotated = r.rightRotation - Node(rightRotated.data, Node(data, left, rightRotated.left), rightRotated.right) - } else sys.error("Should not happen.") - } - - override def doubleRightRotation[B >: A] = { - if (Leaf != left) { - val l: Node[A] = left.asInstanceOf[Node[A]] - // Let's save an instanceOf by 'inlining' the right rotation - val leftRotated = l.leftRotation - Node(leftRotated.data, leftRotated.left, Node(data, leftRotated.right, right)) - } else sys.error("Should not happen.") - } -} - -/** - * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0") - */ -private class AVLIterator[A](root: Node[A]) extends Iterator[A] { - val stack = mutable.ArrayStack[Node[A]](root) - diveLeft() - - private def diveLeft(): Unit = { - if (Leaf != stack.head.left) { - val left: Node[A] = stack.head.left.asInstanceOf[Node[A]] - stack.push(left) - diveLeft() - } - } - - private def engageRight(): Unit = { - if (Leaf != stack.head.right) { - val right: Node[A] = stack.head.right.asInstanceOf[Node[A]] - stack.pop() - stack.push(right) - diveLeft() - } else - stack.pop() - } - - override def hasNext: Boolean = !stack.isEmpty - - override def next(): A = { - if (stack.isEmpty) - throw new NoSuchElementException() - else { - val result = stack.head.data - // Let's maintain stack for the next invocation - engageRight() - result - } - } -} diff --git a/src/library/scala/collection/mutable/PriorityQueue.scala b/src/library/scala/collection/mutable/PriorityQueue.scala index 619beeb1d6..e6889da3b5 100644 --- a/src/library/scala/collection/mutable/PriorityQueue.scala +++ b/src/library/scala/collection/mutable/PriorityQueue.scala @@ -18,8 +18,19 @@ import generic._ * * Only the `dequeue` and `dequeueAll` methods will return elements in priority * order (while removing elements from the heap). Standard collection methods - * including `drop` and `iterator` will remove or traverse the heap in whichever - * order seems most convenient. + * including `drop`, `iterator`, and `toString` will remove or traverse the heap + * in whichever order seems most convenient. + * + * Therefore, printing a `PriorityQueue` will not reveal the priority order of + * the elements, though the highest-priority element will be printed first. To + * print the elements in order, one must duplicate the `PriorityQueue` (by using + * `clone`, for instance) and then dequeue them: + * + * @example {{{ + * val pq = collection.mutable.PriorityQueue(1, 2, 5, 3, 7) + * println(pq) // elements probably not in order + * println(pq.clone.dequeueAll) // prints Vector(7, 5, 3, 2, 1) + * }}} * * @tparam A type of the elements in this priority queue. * @param ord implicit ordering used to compare the elements of type `A`. diff --git a/src/library/scala/concurrent/SyncVar.scala b/src/library/scala/concurrent/SyncVar.scala index 9634f6d900..1ee27b0f36 100644 --- a/src/library/scala/concurrent/SyncVar.scala +++ b/src/library/scala/concurrent/SyncVar.scala @@ -40,7 +40,7 @@ class SyncVar[A] { wait(timeout) val elapsed = System.nanoTime() - start // nanoTime should be monotonic, but it's not possible to rely on that. - // See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6458294. + // See http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6458294. if (elapsed < 0) 0 else TimeUnit.NANOSECONDS.toMillis(elapsed) } diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala index 078ad45be9..3538ac6b94 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -178,7 +178,9 @@ private[concurrent] object Promise { * DefaultPromises, and `linkedRootOf` is currently only designed to be called * by Future.flatMap. */ - final class DefaultPromise[T] extends AtomicReference[AnyRef](Nil) with Promise[T] { + // Left non-final to enable addition of extra fields by Java/Scala converters + // in scala-java8-compat. + class DefaultPromise[T] extends AtomicReference[AnyRef](Nil) with Promise[T] { /** Get the root promise for this promise, compressing the link chain to that * promise if necessary. @@ -248,12 +250,12 @@ private[concurrent] object Promise { @throws(classOf[TimeoutException]) @throws(classOf[InterruptedException]) - def ready(atMost: Duration)(implicit permit: CanAwait): this.type = + final def ready(atMost: Duration)(implicit permit: CanAwait): this.type = if (tryAwait(atMost)) this else throw new TimeoutException("Futures timed out after [" + atMost + "]") @throws(classOf[Exception]) - def result(atMost: Duration)(implicit permit: CanAwait): T = + final def result(atMost: Duration)(implicit permit: CanAwait): T = ready(atMost).value.get.get // ready throws TimeoutException if timeout so value.get is safe here def value: Option[Try[T]] = value0 @@ -265,7 +267,7 @@ private[concurrent] object Promise { case _ => None } - override def isCompleted: Boolean = isCompleted0 + override final def isCompleted: Boolean = isCompleted0 @tailrec private def isCompleted0: Boolean = get() match { @@ -274,7 +276,7 @@ private[concurrent] object Promise { case _ => false } - def tryComplete(value: Try[T]): Boolean = { + final def tryComplete(value: Try[T]): Boolean = { val resolved = resolveTry(value) tryCompleteAndGetListeners(resolved) match { case null => false @@ -297,7 +299,7 @@ private[concurrent] object Promise { } } - def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = + final def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = dispatchOrAddCallback(new CallbackRunnable[T](executor.prepare(), func)) /** Tries to add the callback, if already completed, it dispatches the callback to be executed. diff --git a/src/library/scala/concurrent/util/Unsafe.java b/src/library/scala/concurrent/util/Unsafe.java deleted file mode 100644 index 73739e377d..0000000000 --- a/src/library/scala/concurrent/util/Unsafe.java +++ /dev/null @@ -1,38 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.concurrent.util; -import java.lang.reflect.Field; - -// TODO: remove once akka no longer needs it, hopefully by 2.12.0-M3! -@Deprecated -public final class Unsafe { - @Deprecated - public final static sun.misc.Unsafe instance; - static { - try { - sun.misc.Unsafe found = null; - for(Field field : sun.misc.Unsafe.class.getDeclaredFields()) { - if (field.getType() == sun.misc.Unsafe.class) { - field.setAccessible(true); - found = (sun.misc.Unsafe) field.get(null); - break; - } - } - if (found == null) throw new IllegalStateException("Can't find instance of sun.misc.Unsafe"); - else instance = found; - } catch(Throwable t) { - throw new ExceptionInInitializerError(t); - } - } -} - -// Scala version: -// classOf[sun.misc.Unsafe].getDeclaredFields.filter(_.getType == classOf[sun.misc.Unsafe]).headOption.map { field => -// field.setAccessible(true); field.get(null).asInstanceOf[sun.misc.Unsafe] -// } getOrElse (throw new IllegalStateException("Can't find instance of sun.misc.Unsafe")) diff --git a/src/library/scala/io/Codec.scala b/src/library/scala/io/Codec.scala index 60f99199cb..2a41e25b01 100644 --- a/src/library/scala/io/Codec.scala +++ b/src/library/scala/io/Codec.scala @@ -22,7 +22,7 @@ import scala.language.implicitConversions // <?xml version="1.0" encoding="ISO8859-1" ?> // // MacRoman vs. UTF-8: see http://jira.codehaus.org/browse/JRUBY-3576 -// -Dfile.encoding: see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4375816 +// -Dfile.encoding: see http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4375816 /** A class for character encoding/decoding preferences. * diff --git a/src/library/scala/reflect/ClassManifestDeprecatedApis.scala b/src/library/scala/reflect/ClassManifestDeprecatedApis.scala index ca7a3cddb8..82ec872806 100644 --- a/src/library/scala/reflect/ClassManifestDeprecatedApis.scala +++ b/src/library/scala/reflect/ClassManifestDeprecatedApis.scala @@ -218,7 +218,7 @@ object ClassManifestFactory { /** ClassManifest for the abstract type `prefix # name`. `upperBound` is not * strictly necessary as it could be obtained by reflection. It was * added so that erasure can be calculated without reflection. - * todo: remove after next boostrap + * todo: remove after next bootstrap */ def abstractType[T](prefix: OptManifest[_], name: String, upperbound: ClassManifest[_], args: OptManifest[_]*): ClassManifest[T] = new ClassManifest[T] { @@ -239,4 +239,4 @@ private class ClassTypeManifest[T]( (if (prefix.isEmpty) "" else prefix.get.toString+"#") + (if (runtimeClass.isArray) "Array" else runtimeClass.getName) + argString -}
\ No newline at end of file +} diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index a0d89fc0e1..026d5edd29 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -9,11 +9,10 @@ package scala package runtime -import scala.collection.{ Seq, IndexedSeq, TraversableView, AbstractIterator } +import scala.collection.{ Seq, IndexedSeq, TraversableView, AbstractIterator, GenIterable } import scala.collection.mutable.WrappedArray import scala.collection.immutable.{ StringLike, NumericRange, List, Stream, Nil, :: } import scala.collection.generic.{ Sorted, IsTraversableLike } -import scala.collection.parallel.ParIterable import scala.reflect.{ ClassTag, classTag } import scala.util.control.ControlThrowable import java.lang.{ Class => jClass } @@ -156,7 +155,7 @@ object ScalaRunTime { arr } - // Java bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957 + // Java bug: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4071957 // More background at ticket #2318. def ensureAccessible(m: JMethod): JMethod = scala.reflect.ensureAccessible(m) @@ -326,8 +325,7 @@ object ScalaRunTime { case x if useOwnToString(x) => x.toString case x: AnyRef if isArray(x) => arrayToString(x) case x: scala.collection.Map[_, _] => x.iterator take maxElements map mapInner mkString (x.stringPrefix + "(", ", ", ")") - case x: Iterable[_] => x.iterator take maxElements map inner mkString (x.stringPrefix + "(", ", ", ")") - case x: ParIterable[_] => x.iterator take maxElements map inner mkString (x.stringPrefix + "(", ", ", ")") + case x: GenIterable[_] => x.iterator take maxElements map inner mkString (x.stringPrefix + "(", ", ", ")") case x: Traversable[_] => x take maxElements map inner mkString (x.stringPrefix + "(", ", ", ")") case x: Product1[_] if isTuple(x) => "(" + inner(x._1) + ",)" // that special trailing comma case x: Product if isTuple(x) => x.productIterator map inner mkString ("(", ",", ")") diff --git a/src/library/scala/runtime/Tuple2Zipped.scala b/src/library/scala/runtime/Tuple2Zipped.scala index 512c4fbc27..1c432b0403 100644 --- a/src/library/scala/runtime/Tuple2Zipped.scala +++ b/src/library/scala/runtime/Tuple2Zipped.scala @@ -110,6 +110,8 @@ final class Tuple2Zipped[El1, Repr1, El2, Repr2](val colls: (TraversableLike[El1 return } } + + override def toString = "(%s, %s).zipped".format(colls._1.toString, colls._2.toString) } object Tuple2Zipped { diff --git a/src/library/scala/runtime/Tuple3Zipped.scala b/src/library/scala/runtime/Tuple3Zipped.scala index ffd44acf81..3bab86921b 100644 --- a/src/library/scala/runtime/Tuple3Zipped.scala +++ b/src/library/scala/runtime/Tuple3Zipped.scala @@ -118,6 +118,8 @@ final class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3](val colls: (Travers return } } + + override def toString: String = "(%s, %s, %s).zipped".format(colls._1.toString, colls._2.toString, colls._3.toString) } object Tuple3Zipped { diff --git a/src/library/scala/sys/process/package.scala b/src/library/scala/sys/process/package.scala index 5ec2e73cb9..0e9a1bfc56 100644 --- a/src/library/scala/sys/process/package.scala +++ b/src/library/scala/sys/process/package.scala @@ -157,7 +157,8 @@ package scala.sys { * while(input.read() != -1) count += 1 * input.close() * } - * cat ! new ProcessIO(_.close(), byteCounter, _.close()) + * val p = cat run new ProcessIO(_.close(), byteCounter, _.close()) + * p.exitValue() * count * } * diff --git a/src/library/scala/util/Sorting.scala b/src/library/scala/util/Sorting.scala index ee2bdbc4a7..b4f965f69b 100644 --- a/src/library/scala/util/Sorting.scala +++ b/src/library/scala/util/Sorting.scala @@ -88,7 +88,7 @@ object Sorting { a(pL - 1) = current pL -= 1 case x if x < 0 => - // Already in place. Just update indicies. + // Already in place. Just update indices. iA += 1 case _ if iB > pR => // Wrong side. There's room on the other side, so swap diff --git a/src/library/scala/util/control/Exception.scala b/src/library/scala/util/control/Exception.scala index aa30887ba0..24c297a2fc 100644 --- a/src/library/scala/util/control/Exception.scala +++ b/src/library/scala/util/control/Exception.scala @@ -105,7 +105,7 @@ object Exception { case x if rethrow(x) => throw x case x if pf isDefinedAt x => pf(x) } - finally fin map (_.invoke()) + finally fin foreach (_.invoke()) /* Create an empty Try container with this Catch and the supplied `Finally`. */ def andFinally(body: => Unit): Catch[T] = fin match { diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala index cd7648a44a..f9b49f1730 100644 --- a/src/reflect/scala/reflect/api/Types.scala +++ b/src/reflect/scala/reflect/api/Types.scala @@ -588,7 +588,7 @@ trait Types { /** An extractor class to create and pattern match with syntax `TypeRef(pre, sym, args)` * Here, `pre` is the prefix of the type reference, `sym` is the symbol * referred to by the type reference, and `args` is a possible empty list of - * type argumenrts. + * type arguments. * @group Extractors */ abstract class TypeRefExtractor { diff --git a/src/reflect/scala/reflect/internal/ClassfileConstants.scala b/src/reflect/scala/reflect/internal/ClassfileConstants.scala index e5d97e8959..a4223c1cb5 100644 --- a/src/reflect/scala/reflect/internal/ClassfileConstants.scala +++ b/src/reflect/scala/reflect/internal/ClassfileConstants.scala @@ -14,7 +14,7 @@ object ClassfileConstants { final val JAVA_MAJOR_VERSION = 45 final val JAVA_MINOR_VERSION = 3 - /** (see http://java.sun.com/docs/books/jvms/second_edition/jvms-clarify.html) + /** (see http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.1) * * If the `ACC_INTERFACE` flag is set, the `ACC_ABSTRACT` flag must also * be set (ch. 2.13.1). diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 14487a941b..5ce5c39145 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -233,6 +233,8 @@ trait Definitions extends api.StandardDefinitions { || tp =:= AnyRefTpe ) + def isUnitType(tp: Type) = tp.typeSymbol == UnitClass && tp.annotations.isEmpty + def hasMultipleNonImplicitParamLists(member: Symbol): Boolean = hasMultipleNonImplicitParamLists(member.info) def hasMultipleNonImplicitParamLists(info: Type): Boolean = info match { case PolyType(_, restpe) => hasMultipleNonImplicitParamLists(restpe) @@ -1105,6 +1107,7 @@ trait Definitions extends api.StandardDefinitions { lazy val BridgeClass = requiredClass[scala.annotation.bridge] lazy val ElidableMethodClass = requiredClass[scala.annotation.elidable] lazy val ImplicitNotFoundClass = requiredClass[scala.annotation.implicitNotFound] + lazy val ImplicitAmbiguousClass = getClassIfDefined("scala.annotation.implicitAmbiguous") lazy val MigrationAnnotationClass = requiredClass[scala.annotation.migration] lazy val ScalaStrictFPAttr = requiredClass[scala.annotation.strictfp] lazy val SwitchClass = requiredClass[scala.annotation.switch] diff --git a/src/reflect/scala/reflect/internal/Kinds.scala b/src/reflect/scala/reflect/internal/Kinds.scala index 8ae201f045..902ba9fa80 100644 --- a/src/reflect/scala/reflect/internal/Kinds.scala +++ b/src/reflect/scala/reflect/internal/Kinds.scala @@ -237,7 +237,7 @@ trait Kinds { * * Proper types are represented using ProperTypeKind. * - * Type constructors are reprented using TypeConKind. + * Type constructors are represented using TypeConKind. */ abstract class Kind { import Kind.StringState diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 8a52f0b9d8..05fdfb51ed 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -884,10 +884,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => // string. So this needs attention. For now the fact that migration is // private[scala] ought to provide enough protection. def hasMigrationAnnotation = hasAnnotation(MigrationAnnotationClass) - def migrationMessage = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(0) } - def migrationVersion = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(1) } - def elisionLevel = getAnnotation(ElidableMethodClass) flatMap { _.intArg(0) } - def implicitNotFoundMsg = getAnnotation(ImplicitNotFoundClass) flatMap { _.stringArg(0) } + def migrationMessage = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(0) } + def migrationVersion = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(1) } + def elisionLevel = getAnnotation(ElidableMethodClass) flatMap { _.intArg(0) } + def implicitNotFoundMsg = getAnnotation(ImplicitNotFoundClass) flatMap { _.stringArg(0) } + def implicitAmbiguousMsg = getAnnotation(ImplicitAmbiguousClass) flatMap { _.stringArg(0) } def isCompileTimeOnly = hasAnnotation(CompileTimeOnlyAttr) def compileTimeOnlyMessage = getAnnotation(CompileTimeOnlyAttr) flatMap (_ stringArg 0) @@ -2123,7 +2124,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** The package class containing this symbol, or NoSymbol if there * is not one. * TODO: formulate as enclosingSuchThat, after making sure - * we can start with current symbol rather than onwner. + * we can start with current symbol rather than owner. * TODO: Also harmonize with enclClass, enclMethod etc. */ def enclosingPackageClass: Symbol = { diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index e3f95f9fd8..bbd9df05d2 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -1418,7 +1418,7 @@ trait Trees extends api.Trees { transformTypeDefs(tparams), transform(rhs)) } case LabelDef(name, params, rhs) => - treeCopy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy' + treeCopy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LambdaLifter.proxy' case PackageDef(pid, stats) => treeCopy.PackageDef( tree, transform(pid).asInstanceOf[RefTree], @@ -1601,7 +1601,7 @@ trait Trees extends api.Trees { case _ => // no special handling is required for Function or Import nodes here. // as they don't have interesting infos attached to their symbols. - // Subsitution of the referenced symbol of Return nodes is handled + // Substitution of the referenced symbol of Return nodes is handled // in .ChangeOwnerTraverser } tree match { diff --git a/src/reflect/scala/reflect/internal/transform/UnCurry.scala b/src/reflect/scala/reflect/internal/transform/UnCurry.scala index abea8bed9f..85e3ac60e8 100644 --- a/src/reflect/scala/reflect/internal/transform/UnCurry.scala +++ b/src/reflect/scala/reflect/internal/transform/UnCurry.scala @@ -40,19 +40,27 @@ trait UnCurry { apply(MethodType(h.cloneSymbol.resetFlag(IMPLICIT) :: t, restpe)) case NullaryMethodType(restpe) => apply(MethodType(List(), restpe)) - case TypeRef(pre, ByNameParamClass, arg :: Nil) => - apply(functionType(List(), arg)) - case TypeRef(pre, RepeatedParamClass, arg :: Nil) => - apply(seqType(arg)) - case TypeRef(pre, JavaRepeatedParamClass, arg :: Nil) => - apply(arrayType( - if (isUnboundedGeneric(arg)) ObjectTpe else arg)) + case DesugaredParameterType(desugaredTpe) => + apply(desugaredTpe) case _ => expandAlias(mapOver(tp)) } } } + object DesugaredParameterType { + def unapply(tpe: Type): Option[Type] = tpe match { + case TypeRef(pre, ByNameParamClass, arg :: Nil) => + Some(functionType(List(), arg)) + case TypeRef(pre, RepeatedParamClass, arg :: Nil) => + Some(seqType(arg)) + case TypeRef(pre, JavaRepeatedParamClass, arg :: Nil) => + Some(arrayType(if (isUnboundedGeneric(arg)) ObjectTpe else arg)) + case _ => + None + } + } + private val uncurryType = new TypeMap { def apply(tp0: Type): Type = { val tp = expandAlias(tp0) diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index ea213cadd9..278d081249 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -370,6 +370,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.BridgeClass definitions.ElidableMethodClass definitions.ImplicitNotFoundClass + definitions.ImplicitAmbiguousClass definitions.MigrationAnnotationClass definitions.ScalaStrictFPAttr definitions.SwitchClass @@ -444,7 +445,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.ScalaValueClassesNoUnit definitions.ScalaValueClasses - + uncurry.DesugaredParameterType erasure.GenericArray erasure.scalaErasure erasure.specialScalaErasure diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 841b4abfa5..3b54f5274e 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -133,7 +133,6 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set } catch AbstractOrMissingHandler() } - private def tquoted(s: String) = "\"\"\"" + s + "\"\"\"" private val logScope = scala.sys.props contains "scala.repl.scope" private def scopelog(msg: String) = if (logScope) Console.err.println(msg) @@ -888,7 +887,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set /** Code to import bound names from previous lines - accessPath is code to * append to objectName to access anything bound by request. */ - lazy val ComputedImports(importsPreamble, importsTrailer, accessPath) = + lazy val ComputedImports(headerPreamble, importsPreamble, importsTrailer, accessPath) = exitingTyper(importsCode(referencedNames.toSet, ObjectSourceCode, definesClass)) /** the line of code to compute */ @@ -905,9 +904,13 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set def path = originalPath("$intp") def envLines = { if (!isReplPower) Nil // power mode only for now - else List("def %s = %s".format("$line", tquoted(originalLine)), "def %s = Nil".format("$trees")) + else { + val escapedLine = Constant(originalLine).escapedStringValue + List(s"""def $$line = $escapedLine """, """def $trees = _root_.scala.Nil""") + } } def preamble = s""" + |$headerPreamble |${preambleHeader format lineRep.readName} |${envLines mkString (" ", ";\n ", ";\n")} |$importsPreamble diff --git a/src/repl/scala/tools/nsc/interpreter/Imports.scala b/src/repl/scala/tools/nsc/interpreter/Imports.scala index 3ec77e46f1..5b231d94b6 100644 --- a/src/repl/scala/tools/nsc/interpreter/Imports.scala +++ b/src/repl/scala/tools/nsc/interpreter/Imports.scala @@ -70,7 +70,10 @@ trait Imports { /** Compute imports that allow definitions from previous * requests to be visible in a new request. Returns - * three pieces of related code: + * three or four pieces of related code: + * + * 0. Header code fragment that should go at the beginning + * of the compilation unit, specifically, import Predef. * * 1. An initial code fragment that should go before * the code of the new request. @@ -91,30 +94,34 @@ trait Imports { * (3) It imports multiple same-named implicits, but only the * last one imported is actually usable. */ - case class ComputedImports(prepend: String, append: String, access: String) + case class ComputedImports(header: String, prepend: String, append: String, access: String) protected def importsCode(wanted: Set[Name], wrapper: Request#Wrapper, definesClass: Boolean): ComputedImports = { + val header, code, trailingBraces, accessPath = new StringBuilder + val currentImps = mutable.HashSet[Name]() + var predefEscapes = false // only emit predef import header if name not resolved in history, loosely + /** Narrow down the list of requests from which imports * should be taken. Removes requests which cannot contribute * useful imports for the specified set of wanted names. */ - case class ReqAndHandler(req: Request, handler: MemberHandler) { } + case class ReqAndHandler(req: Request, handler: MemberHandler) def reqsToUse: List[ReqAndHandler] = { /** Loop through a list of MemberHandlers and select which ones to keep. - * 'wanted' is the set of names that need to be imported. + * 'wanted' is the set of names that need to be imported. */ def select(reqs: List[ReqAndHandler], wanted: Set[Name]): List[ReqAndHandler] = { // Single symbol imports might be implicits! See bug #1752. Rather than // try to finesse this, we will mimic all imports for now. def keepHandler(handler: MemberHandler) = handler match { - /* While defining classes in class based mode - implicits are not needed. */ + // While defining classes in class based mode - implicits are not needed. case h: ImportHandler if isClassBased && definesClass => h.importedNames.exists(x => wanted.contains(x)) case _: ImportHandler => true case x => x.definesImplicit || (x.definedNames exists wanted) } reqs match { - case Nil => Nil + case Nil => predefEscapes = wanted contains PredefModule.name ; Nil case rh :: rest if !keepHandler(rh.handler) => select(rest, wanted) case rh :: rest => import rh.handler._ @@ -127,9 +134,6 @@ trait Imports { select(allReqAndHandlers reverseMap { case (r, h) => ReqAndHandler(r, h) }, wanted).reverse } - val code, trailingBraces, accessPath = new StringBuilder - val currentImps = mutable.HashSet[Name]() - // add code for a new object to hold some imports def addWrapper() { import nme.{ INTERPRETER_IMPORT_WRAPPER => iw } @@ -146,6 +150,9 @@ trait Imports { try op finally addWrapper() } + // imports from Predef are relocated to the template header to allow hiding. + def checkHeader(h: ImportHandler) = h.referencedNames contains PredefModule.name + // loop through previous requests, adding imports for each one wrapBeforeAndAfter { // Reusing a single temporary value when import from a line with multiple definitions. @@ -153,6 +160,9 @@ trait Imports { for (ReqAndHandler(req, handler) <- reqsToUse) { val objName = req.lineRep.readPathInstance handler match { + case h: ImportHandler if checkHeader(h) => + header.clear() + header append f"${h.member}%n" // If the user entered an import, then just use it; add an import wrapping // level if the import might conflict with some other import case x: ImportHandler if x.importsWildcard => @@ -194,7 +204,8 @@ trait Imports { } } - ComputedImports(code.toString, trailingBraces.toString, accessPath.toString) + val computedHeader = if (predefEscapes) header.toString else "" + ComputedImports(computedHeader, code.toString, trailingBraces.toString, accessPath.toString) } private def allReqAndHandlers = diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala index 743c2a401c..0353e58e67 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala @@ -787,7 +787,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp if (isReduced) NodeSeq.Empty else { def paramsToHtml(vlsss: List[List[ValueParam]]): NodeSeq = { def param0(vl: ValueParam): NodeSeq = - // notice the }{ in the next lines, they are necessary to avoid an undesired withspace in output + // notice the }{ in the next lines, they are necessary to avoid an undesired whitespace in output <span name={ vl.name }>{ Text(vl.name) }{ Text(": ") ++ typeToHtml(vl.resultType, hasLinks) }{ diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala index 4bed106f43..9381cf3a35 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala @@ -145,7 +145,7 @@ class DotProcess(settings: doc.Settings) { // we shouldn't just sit there for 50s not reporting anything, no? settings.printMsg("Graphviz dot encountered an error when generating the diagram for:") settings.printMsg(templateName) - settings.printMsg("These are usually spurious errors, but if you notice a persistant error on") + settings.printMsg("These are usually spurious errors, but if you notice a persistent error on") settings.printMsg("a diagram, please use the " + settings.docDiagramsDebug.name + " flag and report a bug with the output.") } } |