diff options
124 files changed, 1725 insertions, 489 deletions
@@ -10,6 +10,7 @@ Aleksandar Prokopec <aleksandar.prokopec@epfl.ch> <aleksandar@lampmac14.epfl.ch> Aleksandar Prokopec <aleksandar.prokopec@epfl.ch> <axel22@gmail.com> Alex Cruise <alex@cluonflux.com> Alex Cruise <alex@cluonflux.com> <alex@metaforsoftware.com> +A. P. Marki <som.snytt@gmail.com> Antonio Cunei <antonio.cunei@typesafe.com> Antonio Cunei <antonio.cunei@typesafe.com> <antonio.cunei@epfl.ch> Buraq Emir <buraq@epfl.ch> @@ -71,5 +72,6 @@ Unknown Committer <lost.soul@typesafe.com> <USER@epfl.ch> Unknown Committer <lost.soul@typesafe.com> <noreply@epfl.ch> Viktor Klang <viktor.klang@gmail.com> Vincent Cremet <cremet@epfl.ch> +Vladimir Nikolaev <vladimir.nikolaev9@gmail.com> Vojin Jovanovic <vojin.jovanovic@epfl.ch> Vojin Jovanovic <vojin.jovanovic@epfl.ch> <gvojin@gmail.com> diff --git a/build-ant-macros.xml b/build-ant-macros.xml index 0b92f1dab1..458d1014c2 100644 --- a/build-ant-macros.xml +++ b/build-ant-macros.xml @@ -23,15 +23,35 @@ </sequential> </macrodef> + <!-- Set a property @{name}.cross to the actual cross suffix that should be + used when resolving the module "@{name}". If the (user-supplied) + @{name}.cross.suffix property exists then use that value, otherwise use + "_${scala.binary.version}". --> + <macrodef name="prepareCross"> + <attribute name="name" /> + <sequential> + <if> + <isset property="@{name}.cross.suffix" /> + <then> + <property name="@{name}.cross" value="${@{name}.cross.suffix}" /> + </then> + <else> + <property name="@{name}.cross" value="_${scala.binary.version}" /> + </else> + </if> + </sequential> + </macrodef> + <!-- Set property named @{name} to the jar resolved as @{jar}_${scala.binary.version}:jar. @{jar}_${scala.binary.version} must be a maven dependency. --> <macrodef name="propertyForCrossedArtifact"> <attribute name="name"/> <attribute name="jar"/> + <attribute name="suffix" default="${@{name}.cross}"/> <sequential> - <readProperty name="@{name}" property="@{jar}_${scala.binary.version}:jar"/> - <readProperty name="@{name}-sources" property="@{jar}_${scala.binary.version}:java-source:sources"/> - <readProperty name="@{name}-javadoc" property="@{jar}_${scala.binary.version}:java-source:javadoc"/> + <readProperty name="@{name}" property="@{jar}@{suffix}:jar"/> + <readProperty name="@{name}-sources" property="@{jar}@{suffix}:java-source:sources"/> + <readProperty name="@{name}-javadoc" property="@{jar}@{suffix}:java-source:javadoc"/> </sequential> </macrodef> @@ -276,6 +276,16 @@ TODO: <artifact:remoteRepository id="extra-repo" url="${extra.repo.url}"/> + <!-- prepare, for each of the names below, the property "@{name}.cross", set to the + necessary cross suffix (usually something like "_2.11.0-M6". --> + <prepareCross name="scala-xml" /> + <prepareCross name="scala-parser-combinators" /> + <prepareCross name="scala-continuations-plugin" /> + <prepareCross name="scala-continuations-library"/> + <prepareCross name="scala-swing"/> + <prepareCross name="partest"/> + <prepareCross name="scalacheck"/> + <!-- TODO: delay until absolutely necessary to allow minimal build, also move out partest dependency from scaladoc --> <artifact:dependencies pathId="partest.classpath" filesetId="partest.fileset" versionsId="partest.versions"> <!-- uncomment the following if you're deploying your own partest locally --> @@ -284,13 +294,13 @@ TODO: (we don't distribute partest with Scala, so the risk of sonatype and maven being out of synch is irrelevant): --> <artifact:remoteRepository refid="extra-repo"/> - <dependency groupId="org.scala-lang.modules" artifactId="scala-partest_${scala.binary.version}" version="${partest.version.number}" /> + <dependency groupId="org.scala-lang.modules" artifactId="scala-partest${partest.cross}" version="${partest.version.number}" /> </artifact:dependencies> <copy-deps project="partest"/> <artifact:dependencies pathId="scalacheck.classpath" filesetId="scalacheck.fileset" versionsId="scalacheck.versions"> <artifact:remoteRepository refid="extra-repo"/> - <dependency groupId="org.scalacheck" artifactId="scalacheck_${scala.binary.version}" version="${scalacheck.version.number}" /> + <dependency groupId="org.scalacheck" artifactId="scalacheck${scalacheck.cross}" version="${scalacheck.version.number}" /> </artifact:dependencies> <artifact:dependencies pathId="repl.deps.classpath" filesetId="repl.fileset" versionsId="repl.deps.versions"> @@ -302,11 +312,11 @@ TODO: must specify sourcesFilesetId, javadocFilesetId to download these types of artifacts --> <artifact:dependencies pathId="external-modules.deps.classpath" sourcesFilesetId="external-modules.sources.fileset" javadocFilesetId="external-modules.javadoc.fileset"> <artifact:remoteRepository refid="extra-repo"/> - <dependency groupId="org.scala-lang.modules" artifactId="scala-xml_${scala.binary.version}" version="${scala-xml.version.number}"/> - <dependency groupId="org.scala-lang.modules" artifactId="scala-parser-combinators_${scala.binary.version}" version="${scala-parser-combinators.version.number}"/> - <dependency groupId="org.scala-lang.plugins" artifactId="scala-continuations-plugin_${scala.binary.version}" version="${scala-continuations-plugin.version.number}"/> - <dependency groupId="org.scala-lang.plugins" artifactId="scala-continuations-library_${scala.binary.version}" version="${scala-continuations-library.version.number}"/> - <dependency groupId="org.scala-lang.modules" artifactId="scala-swing_${scala.binary.version}" version="${scala-swing.version.number}"/> + <dependency groupId="org.scala-lang.modules" artifactId="scala-xml${scala-xml.cross}" version="${scala-xml.version.number}"/> + <dependency groupId="org.scala-lang.modules" artifactId="scala-parser-combinators${scala-parser-combinators.cross}" version="${scala-parser-combinators.version.number}"/> + <dependency groupId="org.scala-lang.plugins" artifactId="scala-continuations-plugin${scala-continuations-plugin.cross}" version="${scala-continuations-plugin.version.number}"/> + <dependency groupId="org.scala-lang.plugins" artifactId="scala-continuations-library${scala-continuations-library.cross}" version="${scala-continuations-library.version.number}"/> + <dependency groupId="org.scala-lang.modules" artifactId="scala-swing${scala-swing.cross}" version="${scala-swing.version.number}"/> </artifact:dependencies> <!-- External modules, excluding the core --> @@ -411,8 +421,12 @@ TODO: <condition property="has.java7"> <equals arg1="${ant.java.version}" arg2="1.7"/> </condition> + <condition property="has.java8"> + <equals arg1="${ant.java.version}" arg2="1.8"/> + </condition> <condition property="has.unsupported.jdk"> <not><or> + <isset property="has.java8" /> <isset property="has.java7" /> <isset property="has.java6" /> </or></not> diff --git a/src/compiler/scala/reflect/macros/contexts/Evals.scala b/src/compiler/scala/reflect/macros/contexts/Evals.scala index 84928ddf86..180a998c39 100644 --- a/src/compiler/scala/reflect/macros/contexts/Evals.scala +++ b/src/compiler/scala/reflect/macros/contexts/Evals.scala @@ -12,7 +12,12 @@ trait Evals { private lazy val evalImporter = ru.mkImporter(universe).asInstanceOf[ru.Importer { val from: universe.type }] def eval[T](expr: Expr[T]): T = { - val imported = evalImporter.importTree(expr.tree) - evalToolBox.eval(imported).asInstanceOf[T] + expr.tree match { + case global.Literal(global.Constant(value)) => + value.asInstanceOf[T] + case _ => + val imported = evalImporter.importTree(expr.tree) + evalToolBox.eval(imported).asInstanceOf[T] + } } }
\ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/contexts/Names.scala b/src/compiler/scala/reflect/macros/contexts/Names.scala index c2f14cf0f1..299af40b94 100644 --- a/src/compiler/scala/reflect/macros/contexts/Names.scala +++ b/src/compiler/scala/reflect/macros/contexts/Names.scala @@ -4,7 +4,9 @@ package contexts trait Names { self: Context => - def freshNameCreator = callsiteTyper.context.unit.fresh + import global._ + + def freshNameCreator = globalFreshNameCreator def fresh(): String = freshName() @@ -16,11 +18,25 @@ trait Names { freshName[NameType](name) def freshName(): String = - freshName("fresh$") - - def freshName(name: String): String = - freshNameCreator.newName(name) + freshName(nme.FRESH_PREFIX) + + def freshName(name: String): String = { + // In comparison with the first version of freshName, current "fresh" names + // at least can't clash with legible user-written identifiers and are much less likely to clash with each other. + // It is still not good enough however, because the counter gets reset every time we create a new Global. + // + // This would most certainly cause problems if Scala featured something like introduceTopLevel, + // but even for def macros this can lead to unexpected troubles. Imagine that one Global + // creates a term of an anonymous type with a member featuring a "fresh" name, and then another Global + // imports that term with a wildcard and then generates a "fresh" name of its own. Given unlucky + // circumstances these "fresh" names might end up clashing. + // + // TODO: hopefully SI-7823 will provide an ultimate answer to this problem. + // In the meanwhile I will also keep open the original issue: SI-6879 "c.freshName is broken". + val sortOfUniqueSuffix = freshNameCreator.newName(nme.FRESH_SUFFIX) + name + "$" + sortOfUniqueSuffix + } def freshName[NameType <: Name](name: NameType): NameType = - name.mapName(freshNameCreator.newName(_)).asInstanceOf[NameType] + name.mapName(freshName(_)).asInstanceOf[NameType] }
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 0728fff74f..e3d2bf14a0 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -33,7 +33,7 @@ trait ParsersCommon extends ScannersCommon { self => import global.{currentUnit => _, _} def newLiteral(const: Any) = Literal(Constant(const)) - def literalUnit = newLiteral(()) + def literalUnit = gen.mkSyntheticUnit() /** This is now an abstract class, only to work around the optimizer: * methods in traits are never inlined. @@ -837,8 +837,14 @@ self => if (samePrecedence) checkHeadAssoc(leftAssoc) - def loop(top: Tree): Tree = - if (canReduce) loop(finishBinaryOp(isExpr, popOpInfo(), top)) else top + def loop(top: Tree): Tree = if (canReduce) { + val info = popOpInfo() + if (!isExpr && info.targs.nonEmpty) { + syntaxError(info.offset, "type application is not allowed in pattern") + info.targs.foreach(_.setType(ErrorType)) + } + loop(finishBinaryOp(isExpr, info, top)) + } else top loop(top) } @@ -1219,7 +1225,7 @@ self => // Like Swiss cheese, with holes def stringCheese: Tree = atPos(in.offset) { val start = in.offset - val interpolator = in.name + val interpolator = in.name.encoded // ident() for INTERPOLATIONID val partsBuf = new ListBuffer[Tree] val exprBuf = new ListBuffer[Tree] @@ -2131,8 +2137,6 @@ self => /* -------- PARAMETERS ------------------------------------------- */ - def allowTypelessParams = false - /** {{{ * ParamClauses ::= {ParamClause} [[nl] `(' implicit Params `)'] * ParamClause ::= [nl] `(' [Params] `)' @@ -2147,56 +2151,6 @@ self => def paramClauses(owner: Name, contextBounds: List[Tree], ofCaseClass: Boolean): List[List[ValDef]] = { var implicitmod = 0 var caseParam = ofCaseClass - def param(): ValDef = { - val start = in.offset - val annots = annotations(skipNewLines = false) - var mods = Modifiers(Flags.PARAM) - if (owner.isTypeName) { - mods = modifiers() | Flags.PARAMACCESSOR - if (mods.isLazy) syntaxError("lazy modifier not allowed here. Use call-by-name parameters instead", skipIt = false) - in.token match { - case v @ (VAL | VAR) => - mods = mods withPosition (in.token.toLong, tokenRange(in)) - if (v == VAR) mods |= Flags.MUTABLE - in.nextToken() - case _ => - if (mods.flags != Flags.PARAMACCESSOR) accept(VAL) - if (!caseParam) mods |= Flags.PrivateLocal - } - if (caseParam) mods |= Flags.CASEACCESSOR - } - val nameOffset = in.offset - val name = ident() - var bynamemod = 0 - val tpt = - if (((settings.YmethodInfer && !owner.isTypeName) || allowTypelessParams) && in.token != COLON) { - TypeTree() - } else { // XX-METHOD-INFER - accept(COLON) - if (in.token == ARROW) { - if (owner.isTypeName && !mods.hasLocalFlag) - syntaxError( - in.offset, - (if (mods.isMutable) "`var'" else "`val'") + - " parameters may not be call-by-name", skipIt = false) - else if (implicitmod != 0) - syntaxError( - in.offset, - "implicit parameters may not be call-by-name", skipIt = false) - else bynamemod = Flags.BYNAMEPARAM - } - paramType() - } - val default = - if (in.token == EQUALS) { - in.nextToken() - mods |= Flags.DEFAULTPARAM - expr() - } else EmptyTree - atPos(start, if (name == nme.ERROR) start else nameOffset) { - ValDef((mods | implicitmod.toLong | bynamemod) withAnnotations annots, name.toTermName, tpt, default) - } - } def paramClause(): List[ValDef] = { if (in.token == RPAREN) return Nil @@ -2205,7 +2159,7 @@ self => in.nextToken() implicitmod = Flags.IMPLICIT } - commaSeparated(param()) + commaSeparated(param(owner, implicitmod, caseParam )) } val vds = new ListBuffer[List[ValDef]] val start = in.offset @@ -2253,6 +2207,57 @@ self => } } + def param(owner: Name, implicitmod: Int, caseParam: Boolean): ValDef = { + val start = in.offset + val annots = annotations(skipNewLines = false) + var mods = Modifiers(Flags.PARAM) + if (owner.isTypeName) { + mods = modifiers() | Flags.PARAMACCESSOR + if (mods.isLazy) syntaxError("lazy modifier not allowed here. Use call-by-name parameters instead", skipIt = false) + in.token match { + case v @ (VAL | VAR) => + mods = mods withPosition (in.token.toLong, tokenRange(in)) + if (v == VAR) mods |= Flags.MUTABLE + in.nextToken() + case _ => + if (mods.flags != Flags.PARAMACCESSOR) accept(VAL) + if (!caseParam) mods |= Flags.PrivateLocal + } + if (caseParam) mods |= Flags.CASEACCESSOR + } + val nameOffset = in.offset + val name = ident() + var bynamemod = 0 + val tpt = + if ((settings.YmethodInfer && !owner.isTypeName) && in.token != COLON) { + TypeTree() + } else { // XX-METHOD-INFER + accept(COLON) + if (in.token == ARROW) { + if (owner.isTypeName && !mods.hasLocalFlag) + syntaxError( + in.offset, + (if (mods.isMutable) "`var'" else "`val'") + + " parameters may not be call-by-name", skipIt = false) + else if (implicitmod != 0) + syntaxError( + in.offset, + "implicit parameters may not be call-by-name", skipIt = false) + else bynamemod = Flags.BYNAMEPARAM + } + paramType() + } + val default = + if (in.token == EQUALS) { + in.nextToken() + mods |= Flags.DEFAULTPARAM + expr() + } else EmptyTree + atPos(start, if (name == nme.ERROR) start else nameOffset) { + ValDef((mods | implicitmod.toLong | bynamemod) withAnnotations annots, name.toTermName, tpt, default) + } + } + /** {{{ * TypeParamClauseOpt ::= [TypeParamClause] * TypeParamClause ::= `[' VariantTypeParam {`,' VariantTypeParam} `]'] diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 8011abc1ed..e8d46704c3 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -475,14 +475,17 @@ trait Scanners extends ScannersCommon { if (token == INTERPOLATIONID) { nextRawChar() if (ch == '\"') { - nextRawChar() - if (ch == '\"') { + val lookahead = lookaheadReader + lookahead.nextChar() + if (lookahead.ch == '\"') { + nextRawChar() // now eat it offset += 3 nextRawChar() getStringPart(multiLine = true) sepRegions = STRINGPART :: sepRegions // indicate string part sepRegions = STRINGLIT :: sepRegions // once more to indicate multi line string part } else { + nextChar() token = STRINGLIT strVal = "" } diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index cfee988efc..525dcffb0c 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -56,7 +56,7 @@ abstract class TreeBuilder { /** Create tree representing (unencoded) binary operation expression or pattern. */ def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position, targs: List[Tree] = Nil): Tree = { - require(isExpr || targs.isEmpty, s"Incompatible args to makeBinop: !isExpr but targs=$targs") + require(isExpr || targs.isEmpty || targs.exists(_.isErroneous), s"Incompatible args to makeBinop: !isExpr but targs=$targs") def mkSelection(t: Tree) = { def sel = atPos(opPos union t.pos)(Select(stripParens(t), op.encode)) diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 1332d01dbd..b650cdfa09 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -46,8 +46,10 @@ abstract class GenICode extends SubComponent { var unit: CompilationUnit = NoCompilationUnit override def run() { - scalaPrimitives.init() - classes.clear() + if (!settings.isBCodeActive) { + scalaPrimitives.init() + classes.clear() + } super.run() } @@ -1007,8 +1009,15 @@ abstract class GenICode extends SubComponent { } // emit conversion - if (generatedType != expectedType) - adapt(generatedType, expectedType, resCtx, tree.pos) + if (generatedType != expectedType) { + tree match { + case Literal(Constant(null)) if generatedType == NullReference => + // literal null on the stack (as opposed to a boxed null, see SI-8233), + // we can bypass `adapt` which would otherwise emitt a redundant [DROP, CONSTANT(null)] + case _ => + adapt(generatedType, expectedType, resCtx, tree.pos) + } + } resCtx } @@ -1058,6 +1067,9 @@ abstract class GenICode extends SubComponent { case (NothingReference, _) => ctx.bb.emit(THROW(ThrowableClass)) ctx.bb.enterIgnoreMode() + case (NullReference, REFERENCE(_)) => + // SI-8223 we can't assume that the stack contains a `null`, it might contain a Null$ + ctx.bb.emit(Seq(DROP(from), CONSTANT(Constant(null)))) case _ if from isAssignabledTo to => () case (_, UNIT) => diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index 267fa15312..64146585e5 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -21,7 +21,7 @@ trait Members { import global._ - object NoCode extends Code(null, "NoCode") { + object NoCode extends Code(null, TermName("NoCode")) { override def blocksList: List[BasicBlock] = Nil } @@ -29,8 +29,8 @@ trait Members { * This class represents the intermediate code of a method or * other multi-block piece of code, like exception handlers. */ - class Code(method: IMethod, name: String) { - def this(method: IMethod) = this(method, method.symbol.decodedName.toString.intern) + class Code(method: IMethod, name: Name) { + def this(method: IMethod) = this(method, method.symbol.name) /** The set of all blocks */ val blocks = mutable.ListBuffer[BasicBlock]() @@ -82,7 +82,7 @@ trait Members { } /** This methods returns a string representation of the ICode */ - override def toString = "ICode '" + name + "'" + override def toString = "ICode '" + name.decoded + "'" /* Compute a unique new label */ def nextLabel: Int = { diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 90c15bca61..55f45257dc 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -55,23 +55,26 @@ abstract class Pickler extends SubComponent { case _ => } } - // If there are any erroneous types in the tree, then we will crash - // when we pickle it: so let's report an error instead. We know next - // to nothing about what happened, but our supposition is a lot better - // than "bad type: <error>" in terms of explanatory power. - for (t <- unit.body) { - if (t.isErroneous) { - unit.error(t.pos, "erroneous or inaccessible type") - return - } - if (!t.isDef && t.hasSymbolField && t.symbol.isTermMacro) { - unit.error(t.pos, "macro has not been expanded") - return - } + try { + pickle(unit.body) + } catch { + case e: FatalError => + for (t <- unit.body) { + // If there are any erroneous types in the tree, then we will crash + // when we pickle it: so let's report an error instead. We know next + // to nothing about what happened, but our supposition is a lot better + // than "bad type: <error>" in terms of explanatory power. + // + // OPT: do this only as a recovery after fatal error. Checking in advance was expensive. + if (t.isErroneous) { + if (settings.debug) e.printStackTrace() + unit.error(t.pos, "erroneous or inaccessible type") + return + } + } + throw e } - - pickle(unit.body) } } diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 4bbfc945f6..ccfddab94a 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -92,11 +92,22 @@ abstract class Erasure extends AddInterfaces // more rigorous way up front rather than catching it after the fact, // but that will be more involved. private def dotCleanup(sig: String): String = { + // OPT 50% of time in generic signatures (~1% of compile time) was in this method, hence the imperative rewrite. var last: Char = '\u0000' - sig map { - case '.' if last != '>' => last = '.' ; '$' - case ch => last = ch ; ch + var i = 0 + val len = sig.length + val copy: Array[Char] = sig.toCharArray + var changed = false + while (i < sig.length) { + val ch = copy(i) + if (ch == '.' && last != '>') { + copy(i) = '$' + changed = true + } + last = ch + i += 1 } + if (changed) new String(copy) else sig } /** This object is only used for sanity testing when -check:genjvm is set. @@ -522,6 +533,8 @@ abstract class Erasure extends AddInterfaces class Eraser(_context: Context) extends Typer(_context) with TypeAdapter { val typer = this.asInstanceOf[analyzer.Typer] + override protected def stabilize(tree: Tree, pre: Type, mode: Mode, pt: Type): Tree = tree + /** Replace member references as follows: * * - `x == y` for == in class Any becomes `x equals y` with equals in class Object. @@ -760,7 +773,7 @@ abstract class Erasure extends AddInterfaces || super.exclude(sym) || !sym.hasTypeAt(currentRun.refchecksPhase.id) ) - override def matches(sym1: Symbol, sym2: Symbol) = true + override def matches(lo: Symbol, high: Symbol) = true } def isErasureDoubleDef(pair: SymbolPair) = { import pair._ diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala index 4222c4d8c8..870eafbf20 100644 --- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala +++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala @@ -24,15 +24,16 @@ abstract class OverridingPairs extends SymbolPairs { /** Symbols to exclude: Here these are constructors and private/artifact symbols, * including bridges. But it may be refined in subclasses. */ - override protected def exclude(sym: Symbol) = (sym hasFlag PRIVATE | ARTIFACT) || sym.isConstructor + override protected def exclude(sym: Symbol) = sym.isPrivateLocal || sym.isArtifact || sym.isConstructor /** Types always match. Term symbols match if their member types * relative to `self` match. */ - override protected def matches(sym1: Symbol, sym2: Symbol) = sym1.isType || ( - (sym1.owner != sym2.owner) - && !exclude(sym2) - && relatively.matches(sym1, sym2) - ) + override protected def matches(lo: Symbol, high: Symbol) = lo.isType || ( + (lo.owner != high.owner) // don't try to form pairs from overloaded members + && !high.isPrivate // private or private[this] members never are overriden + && !exclude(lo) // this admits private, as one can't have a private member that matches a less-private member. + && relatively.matches(lo, high) + ) // TODO we don't call exclude(high), should we? } } diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 3791af1629..c59b726076 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -306,6 +306,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Return the specialized name of 'sym' in the given environment. It * guarantees the same result regardless of the map order by sorting * type variables alphabetically. + * + * !!! Is this safe in the face of the following? + * scala> trait T { def foo[A] = 0}; object O extends T { override def foo[B] = 0 } */ private def specializedName(sym: Symbol, env: TypeEnv): TermName = { val tvars = ( @@ -391,13 +394,16 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * enclosing member with the annotation. */ private def needsSpecialization(env: TypeEnv, sym: Symbol): Boolean = ( - !sym.ownerChain.exists(_ hasAnnotation UnspecializedClass) && ( + !hasUnspecializableAnnotation(sym) && ( specializedTypeVars(sym).intersect(env.keySet).diff(wasSpecializedForTypeVars(sym)).nonEmpty || sym.isClassConstructor && (sym.enclClass.typeParams exists (_.isSpecialized)) || isNormalizedMember(sym) && info(sym).typeBoundsIn(env) ) ) + private def hasUnspecializableAnnotation(sym: Symbol): Boolean = + sym.ownerChain.exists(_ hasAnnotation UnspecializedClass) + def isNormalizedMember(m: Symbol) = m.isSpecialized && (info get m exists { case NormalizedMember(_) => true case _ => false @@ -433,10 +439,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { else specializedTypeVars(sym.typeParams zip args collect { case (tp, arg) if tp.isSpecialized => arg }) - case PolyType(tparams, resTpe) => specializedTypeVars(resTpe :: tparams.map(_.info)) + case PolyType(tparams, resTpe) => specializedTypeVars(resTpe :: mapList(tparams)(symInfo)) // OPT // since this method may be run at phase typer (before uncurry, where NMTs are eliminated) case NullaryMethodType(resTpe) => specializedTypeVars(resTpe) - case MethodType(argSyms, resTpe) => specializedTypeVars(resTpe :: argSyms.map(_.tpe)) + case MethodType(argSyms, resTpe) => specializedTypeVars(resTpe :: mapList(argSyms)(symTpe)) // OPT case ExistentialType(_, res) => specializedTypeVars(res) case AnnotatedType(_, tp) => specializedTypeVars(tp) case TypeBounds(lo, hi) => specializedTypeVars(lo :: hi :: Nil) @@ -907,16 +913,20 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } if (sym.isMethod) { - val stvars = specializedTypeVars(sym) - if (stvars.nonEmpty) - debuglog("specialized %s on %s".format(sym.fullLocationString, stvars.map(_.name).mkString(", "))) + if (hasUnspecializableAnnotation(sym)) { + List() + } else { + val stvars = specializedTypeVars(sym) + if (stvars.nonEmpty) + debuglog("specialized %s on %s".format(sym.fullLocationString, stvars.map(_.name).mkString(", "))) - val tps1 = if (sym.isConstructor) tps filter (sym.info.paramTypes contains _) else tps - val tps2 = tps1 filter stvars - if (!sym.isDeferred) - addConcreteSpecMethod(sym) + val tps1 = if (sym.isConstructor) tps filter (sym.info.paramTypes contains _) else tps + val tps2 = tps1 filter stvars + if (!sym.isDeferred) + addConcreteSpecMethod(sym) - specializeOn(tps2) + specializeOn(tps2) + } } else Nil } diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index b471d16ddd..5973c70583 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -128,6 +128,7 @@ abstract class TailCalls extends Transform { logResult(msg)(method.newValue(nme.THIS, pos, SYNTHETIC) setInfo currentClass.typeOfThis) } override def toString = s"${method.name} tparams=$tparams tailPos=$tailPos label=$label label info=${label.info}" + } object EmptyTailContext extends TailContext { @@ -185,6 +186,18 @@ abstract class TailCalls extends Transform { private def noTailContext() = new ClonedTailContext(ctx, tailPos = false) private def yesTailContext() = new ClonedTailContext(ctx, tailPos = true) + + override def transformUnit(unit: CompilationUnit): Unit = { + try { + super.transformUnit(unit) + } finally { + // OPT clear these after each compilation unit + failPositions.clear() + failReasons.clear() + accessed.clear() + } + } + /** Rewrite this tree to contain no tail recursive calls */ def transform(tree: Tree, nctx: TailContext): Tree = { val saved = ctx @@ -218,12 +231,12 @@ abstract class TailCalls extends Transform { */ def fail(reason: String) = { debuglog("Cannot rewrite recursive call at: " + fun.pos + " because: " + reason) - failReasons(ctx) = reason + if (ctx.isMandatory) failReasons(ctx) = reason treeCopy.Apply(tree, noTailTransform(target), transformArgs) } /* Position of failure is that of the tree being considered. */ def failHere(reason: String) = { - failPositions(ctx) = fun.pos + if (ctx.isMandatory) failPositions(ctx) = fun.pos fail(reason) } def rewriteTailCall(recv: Tree): Tree = { @@ -237,7 +250,8 @@ abstract class TailCalls extends Transform { if (!ctx.isEligible) fail("it is neither private nor final so can be overridden") else if (!isRecursiveCall) { - if (receiverIsSuper) failHere("it contains a recursive call targeting a supertype") + if (ctx.isMandatory && receiverIsSuper) // OPT expensive check, avoid unless we will actually report the error + failHere("it contains a recursive call targeting a supertype") else failHere(defaultReason) } else if (!matchesTypeArgs) failHere("it is called recursively with different type arguments") @@ -245,6 +259,11 @@ abstract class TailCalls extends Transform { else if (!receiverIsSame) failHere("it changes type of 'this' on a polymorphic recursive call") else rewriteTailCall(receiver) } + + def isEligible(tree: DefDef) = { + val sym = tree.symbol + !(sym.hasAccessorFlag || sym.isConstructor) + } tree match { case ValDef(_, _, _, _) => @@ -253,7 +272,7 @@ abstract class TailCalls extends Transform { super.transform(tree) - case dd @ DefDef(_, name, _, vparamss0, _, rhs0) if !dd.symbol.hasAccessorFlag => + case dd @ DefDef(_, name, _, vparamss0, _, rhs0) if isEligible(dd) => val newCtx = new DefDefTailContext(dd) if (newCtx.isMandatory && !(newCtx containsRecursiveCall rhs0)) unit.error(tree.pos, "@tailrec annotated method contains no recursive calls") diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index e193cf3de2..e7ea686bc8 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -105,12 +105,11 @@ abstract class UnCurry extends InfoTransform */ def isByNameRef(tree: Tree) = ( tree.isTerm - && !byNameArgs(tree) && (tree.symbol ne null) && (isByName(tree.symbol)) + && !byNameArgs(tree) ) - // ------- Handling non-local returns ------------------------------------------------- /** The type of a non-local return expression with given argument type */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala index 94f8f509fc..b899cd8994 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala @@ -186,7 +186,7 @@ trait Checkable { * additional conditions holds: * - either A or B is effectively final * - neither A nor B is a trait (i.e. both are actual classes, not eligible for mixin) - * - both A and B are sealed, and every possible pairing of their children is irreconcilable + * - both A and B are sealed/final, and every possible pairing of their children is irreconcilable * * TODO: the last two conditions of the last possibility (that the symbols are not of * classes being compiled in the current run) are because this currently runs too early, @@ -198,8 +198,9 @@ trait Checkable { isEffectivelyFinal(sym1) // initialization important || isEffectivelyFinal(sym2) || !sym1.isTrait && !sym2.isTrait - || sym1.isSealed && sym2.isSealed && allChildrenAreIrreconcilable(sym1, sym2) && !currentRun.compiles(sym1) && !currentRun.compiles(sym2) + || isSealedOrFinal(sym1) && isSealedOrFinal(sym2) && allChildrenAreIrreconcilable(sym1, sym2) && !currentRun.compiles(sym1) && !currentRun.compiles(sym2) ) + private def isSealedOrFinal(sym: Symbol) = sym.isSealed || sym.isFinal private def isEffectivelyFinal(sym: Symbol): Boolean = ( // initialization important sym.initialize.isEffectivelyFinal || ( diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 4d0eda2377..2043eb5d5d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -418,7 +418,7 @@ trait ContextErrors { case TypeRef(_, _, arg :: _) if arg.typeSymbol == TupleClass(funArity) && funArity > 1 => sm"""| |Note: The expected type requires a one-argument function accepting a $funArity-Tuple. - | Consider a pattern matching anoynmous function, `{ case $example => ... }`""" + | Consider a pattern matching anonymous function, `{ case $example => ... }`""" case _ => "" } case _ => "" diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 598b12b00d..e5907e1a0f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -1303,7 +1303,7 @@ trait Contexts { self: Analyzer => var renamed = false var selectors = tree.selectors def current = selectors.head - while (selectors.nonEmpty && result == NoSymbol) { + while ((selectors ne Nil) && result == NoSymbol) { if (current.rename == name.toTermName) result = qual.tpe.nonLocalMember( // new to address #2733: consider only non-local members for imports if (name.isTypeName) current.name.toTypeName else current.name) diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 91321d4700..776920ed42 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -137,10 +137,6 @@ trait Implicits { private val improvesCache = perRunCaches.newMap[(ImplicitInfo, ImplicitInfo), Boolean]() private val implicitSearchId = { var id = 1 ; () => try id finally id += 1 } - private def isInvalidConversionTarget(tpe: Type): Boolean = tpe match { - case Function1(_, out) => AnyRefClass.tpe <:< out - case _ => false - } private def isInvalidConversionSource(tpe: Type): Boolean = tpe match { case Function1(in, _) => in <:< NullClass.tpe case _ => false @@ -629,7 +625,8 @@ trait Implicits { // for instance, if we have `class C[T]` and `implicit def conv[T: Numeric](c: C[T]) = ???` // then Scaladoc will give us something of type `C[T]`, and it would like to know // that `conv` is potentially available under such and such conditions - case tree if isImplicitMethodType(tree.tpe) && !isScalaDoc => applyImplicitArgs(tree) + case tree if isImplicitMethodType(tree.tpe) && !isScalaDoc => + applyImplicitArgs(tree) case tree => tree } case _ => fallback @@ -791,7 +788,7 @@ trait Implicits { final class LocalShadower extends Shadower { val shadowed = util.HashSet[Name](512) def addInfos(infos: Infos) { - shadowed addEntries infos.map(_.name) + infos.foreach(i => shadowed.addEntry(i.name)) } def isShadowed(name: Name) = shadowed(name) } @@ -808,7 +805,6 @@ trait Implicits { private def isIneligible(info: ImplicitInfo) = ( info.isCyclicOrErroneous || isView && (info.sym eq Predef_conforms) - || shadower.isShadowed(info.name) || (!context.macrosEnabled && info.sym.isTermMacro) ) @@ -817,6 +813,7 @@ trait Implicits { def survives(info: ImplicitInfo) = ( !isIneligible(info) // cyclic, erroneous, shadowed, or specially excluded && isPlausiblyCompatible(info.tpe, wildPt) // optimization to avoid matchesPt + && !shadower.isShadowed(info.name) // OPT rare, only check for plausible candidates && matchesPt(info) // stable and matches expected type ) /** The implicits that are not valid because they come later in the source and @@ -1361,11 +1358,17 @@ trait Implicits { if (context.ambiguousErrors) context.issueAmbiguousError(AmbiguousImplicitTypeError(tree, msg)) } - if (isInvalidConversionTarget(pt)) { - maybeInvalidConversionError("the result type of an implicit conversion must be more specific than AnyRef") - result = SearchFailure + pt match { + case Function1(_, out) => + def prohibit(sym: Symbol) = if (sym.tpe <:< out) { + maybeInvalidConversionError(s"the result type of an implicit conversion must be more specific than ${sym.name}") + result = SearchFailure + } + prohibit(AnyRefClass) + if (settings.isScala211) prohibit(AnyValClass) + case _ => false } - else if (settings.isScala211 && isInvalidConversionSource(pt)) { + if (settings.isScala211 && isInvalidConversionSource(pt)) { maybeInvalidConversionError("an expression of type Null is ineligible for implicit conversion") result = SearchFailure } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index dd0923a696..997fd6fc65 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -595,6 +595,7 @@ trait Infer extends Checkable { } private[typechecker] def followApply(tp: Type): Type = tp match { + case _ if tp.isError => tp // SI-8228, `ErrorType nonPrivateMember nme.apply` returns an member with an erroneous type! case NullaryMethodType(restp) => val restp1 = followApply(restp) if (restp1 eq restp) tp else restp1 diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 27e8698676..645f267a21 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1069,8 +1069,9 @@ trait Namers extends MethodSynthesis { } def overriddenSymbol(resTp: Type) = { + lazy val schema: Type = methodTypeSchema(resTp) // OPT create once. Must be lazy to avoid cycles in neg/t5093.scala intersectionType(methOwner.info.parents).nonPrivateMember(meth.name).filter { sym => - sym != NoSymbol && (site.memberType(sym) matches methodTypeSchema(resTp)) + sym != NoSymbol && (site.memberType(sym) matches schema) } } // TODO: see whether this or something similar would work instead: diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 68d724b6fc..f7684b93af 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1596,6 +1596,10 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } } + private def checkUnexpandedMacro(t: Tree) = + if (!t.isDef && t.hasSymbolField && t.symbol.isTermMacro) + unit.error(t.pos, "macro has not been expanded") + override def transform(tree: Tree): Tree = { val savedLocalTyper = localTyper val savedCurrentApplication = currentApplication @@ -1755,6 +1759,9 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans varianceValidator.traverse(tt.original) // See SI-7872 case _ => } + + checkUnexpandedMacro(result) + result } catch { case ex: TypeError => diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala index 995f98cc2c..57f27a05fd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala +++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala @@ -46,7 +46,7 @@ trait StdAttachments { * The parameter is of type `Any`, because macros can expand both into trees and into annotations. */ def hasMacroExpansionAttachment(any: Any): Boolean = any match { - case tree: Tree => tree.attachments.get[MacroExpansionAttachment].isDefined + case tree: Tree => tree.hasAttachment[MacroExpansionAttachment] case _ => false } @@ -96,7 +96,7 @@ trait StdAttachments { */ def isMacroExpansionSuppressed(tree: Tree): Boolean = ( settings.Ymacroexpand.value == settings.MacroExpand.None // SI-6812 - || tree.attachments.get[SuppressMacroExpansionAttachment.type].isDefined + || tree.hasAttachment[SuppressMacroExpansionAttachment.type] || (tree match { // we have to account for the fact that during typechecking an expandee might become wrapped, // i.e. surrounded by an inferred implicit argument application or by an inferred type argument application. @@ -150,7 +150,7 @@ trait StdAttachments { /** Determines whether a tree should or should not be adapted, * because someone has put MacroImplRefAttachment on it. */ - def isMacroImplRef(tree: Tree): Boolean = tree.attachments.get[MacroImplRefAttachment.type].isDefined + def isMacroImplRef(tree: Tree): Boolean = tree.hasAttachment[MacroImplRefAttachment.type] /** Since mkInvoke, the applyDynamic/selectDynamic/etc desugarer, is disconnected * from typedNamedApply, the applyDynamicNamed argument rewriter, the latter diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9776b1e80e..101e1526fe 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -579,7 +579,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper * 3. Turn tree type into stable type if possible and required by context. * 4. Give getClass calls a more precise type based on the type of the target of the call. */ - private def stabilize(tree: Tree, pre: Type, mode: Mode, pt: Type): Tree = { + protected def stabilize(tree: Tree, pre: Type, mode: Mode, pt: Type): Tree = { + // Side effect time! Don't be an idiot like me and think you // can move "val sym = tree.symbol" before this line, because // inferExprAlternative side-effects the tree's symbol. @@ -992,7 +993,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def adaptMismatchedSkolems() = { def canIgnoreMismatch = ( !context.reportErrors && isPastTyper - || tree.attachments.get[MacroExpansionAttachment].isDefined + || tree.hasAttachment[MacroExpansionAttachment] ) def bound = pt match { case ExistentialType(qs, _) => qs @@ -2232,14 +2233,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper DeprecatedParamNameError(p, n) } } - } - if (meth.isStructuralRefinementMember) - checkMethodStructuralCompatible(ddef) + if (meth.isStructuralRefinementMember) + checkMethodStructuralCompatible(ddef) - if (meth.isImplicit && !meth.isSynthetic) meth.info.paramss match { - case List(param) :: _ if !param.isImplicit => - checkFeature(ddef.pos, ImplicitConversionsFeature, meth.toString) - case _ => + if (meth.isImplicit && !meth.isSynthetic) meth.info.paramss match { + case List(param) :: _ if !param.isImplicit => + checkFeature(ddef.pos, ImplicitConversionsFeature, meth.toString) + case _ => + } } treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType @@ -3411,7 +3412,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // instantiate dependent method types, must preserve singleton types where possible (stableTypeFor) -- example use case: // val foo = "foo"; def precise(x: String)(y: x.type): x.type = {...}; val bar : foo.type = precise(foo)(foo) // precise(foo) : foo.type => foo.type - val restpe = mt.resultType(args1 map (arg => gen stableTypeFor arg orElse arg.tpe)) + val restpe = mt.resultType(mapList(args1)(arg => gen stableTypeFor arg orElse arg.tpe)) def ifPatternSkipFormals(tp: Type) = tp match { case MethodType(_, rtp) if (mode.inPatternMode) => rtp case _ => tp @@ -3831,7 +3832,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // lifted out of typed1 because it's needed in typedImplicit0 protected def typedTypeApply(tree: Tree, mode: Mode, fun: Tree, args: List[Tree]): Tree = fun.tpe match { case OverloadedType(pre, alts) => - inferPolyAlternatives(fun, args map (_.tpe)) + inferPolyAlternatives(fun, mapList(args)(treeTpe)) val tparams = fun.symbol.typeParams //@M TODO: fun.symbol.info.typeParams ? (as in typedAppliedTypeTree) val args1 = if (sameLength(args, tparams)) { //@M: in case TypeApply we can't check the kind-arities of the type arguments, @@ -3851,7 +3852,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper typedTypeApply(tree, mode, fun setType fun.tpe.widen, args) case PolyType(tparams, restpe) if tparams.nonEmpty => if (sameLength(tparams, args)) { - val targs = args map (_.tpe) + val targs = mapList(args)(treeTpe) checkBounds(tree, NoPrefix, NoSymbol, tparams, targs, "") if (isPredefClassOf(fun.symbol)) typedClassOf(tree, args.head, noGen = true) @@ -4871,7 +4872,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper typedHigherKindedType(arg, mode, pt) } - val argtypes = args1 map (_.tpe) + val argtypes = mapList(args1)(treeTpe) foreach2(args, tparams) { (arg, tparam) => // note: can't use args1 in selector, because Binds got replaced diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala index 8a54519401..2027d43264 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala @@ -31,26 +31,28 @@ trait Holes { self: Quasiquotes => import definitions._ import universeTypes._ - protected lazy val IterableTParam = IterableClass.typeParams(0).asType.toType - protected def inferParamImplicit(tfun: Type, targ: Type) = c.inferImplicitValue(appliedType(tfun, List(targ)), silent = true) - protected def inferLiftable(tpe: Type): Tree = inferParamImplicit(liftableType, tpe) - protected def inferUnliftable(tpe: Type): Tree = inferParamImplicit(unliftableType, tpe) - protected def isLiftableType(tpe: Type) = inferLiftable(tpe) != EmptyTree - protected def isNativeType(tpe: Type) = + private lazy val IterableTParam = IterableClass.typeParams(0).asType.toType + private def inferParamImplicit(tfun: Type, targ: Type) = c.inferImplicitValue(appliedType(tfun, List(targ)), silent = true) + private def inferLiftable(tpe: Type): Tree = inferParamImplicit(liftableType, tpe) + private def inferUnliftable(tpe: Type): Tree = inferParamImplicit(unliftableType, tpe) + private def isLiftableType(tpe: Type) = inferLiftable(tpe) != EmptyTree + private def isNativeType(tpe: Type) = (tpe <:< treeType) || (tpe <:< nameType) || (tpe <:< modsType) || (tpe <:< flagsType) || (tpe <:< symbolType) - protected def isBottomType(tpe: Type) = + private def isBottomType(tpe: Type) = tpe <:< NothingClass.tpe || tpe <:< NullClass.tpe - protected def stripIterable(tpe: Type, limit: Option[Cardinality] = None): (Cardinality, Type) = + private def extractIterableTParam(tpe: Type) = + IterableTParam.asSeenFrom(tpe, IterableClass) + private def stripIterable(tpe: Type, limit: Option[Cardinality] = None): (Cardinality, Type) = if (limit.map { _ == NoDot }.getOrElse { false }) (NoDot, tpe) else if (tpe != null && !isIterableType(tpe)) (NoDot, tpe) else if (isBottomType(tpe)) (NoDot, tpe) else { - val targ = IterableTParam.asSeenFrom(tpe, IterableClass) + val targ = extractIterableTParam(tpe) val (card, innerTpe) = stripIterable(targ, limit.map { _.pred }) (card.succ, innerTpe) } - protected def iterableTypeFromCard(n: Cardinality, tpe: Type): Type = { + private def iterableTypeFromCard(n: Cardinality, tpe: Type): Type = { if (n == NoDot) tpe else appliedType(IterableClass.toType, List(iterableTypeFromCard(n.pred, tpe))) } @@ -74,8 +76,7 @@ trait Holes { self: Quasiquotes => class ApplyHole(card: Cardinality, splicee: Tree) extends Hole { val (strippedTpe, tpe): (Type, Type) = { - if (stripIterable(splicee.tpe)._1.value < card.value) cantSplice() - val (_, strippedTpe) = stripIterable(splicee.tpe, limit = Some(card)) + val (strippedCard, strippedTpe) = stripIterable(splicee.tpe, limit = Some(card)) if (isBottomType(strippedTpe)) cantSplice() else if (isNativeType(strippedTpe)) (strippedTpe, iterableTypeFromCard(card, strippedTpe)) else if (isLiftableType(strippedTpe)) (strippedTpe, iterableTypeFromCard(card, treeType)) @@ -88,14 +89,14 @@ trait Holes { self: Quasiquotes => else if (isLiftableType(itpe)) lifted(itpe)(tree) else global.abort("unreachable") if (card == NoDot) inner(strippedTpe)(splicee) - else iterated(card, strippedTpe, inner(strippedTpe))(splicee) + else iterated(card, splicee, splicee.tpe) } val pos = splicee.pos val cardinality = stripIterable(tpe)._1 - protected def cantSplice(): Nothing = { + private def cantSplice(): Nothing = { val (iterableCard, iterableType) = stripIterable(splicee.tpe) val holeCardMsg = if (card != NoDot) s" with $card" else "" val action = "splice " + splicee.tpe + holeCardMsg @@ -111,28 +112,66 @@ trait Holes { self: Quasiquotes => c.abort(splicee.pos, s"Can't $action, $advice") } - protected def lifted(tpe: Type)(tree: Tree): Tree = { + private def lifted(tpe: Type)(tree: Tree): Tree = { val lifter = inferLiftable(tpe) assert(lifter != EmptyTree, s"couldnt find a liftable for $tpe") val lifted = Apply(lifter, List(tree)) atPos(tree.pos)(lifted) } - protected def iterated(card: Cardinality, tpe: Type, elementTransform: Tree => Tree = identity)(tree: Tree): Tree = { - assert(card != NoDot) - def reifyIterable(tree: Tree, n: Cardinality): Tree = { - def loop(tree: Tree, n: Cardinality): Tree = - if (n == NoDot) elementTransform(tree) - else { - val x: TermName = c.freshName() - val wrapped = reifyIterable(Ident(x), n.pred) - val xToWrapped = Function(List(ValDef(Modifiers(PARAM), x, TypeTree(), EmptyTree)), wrapped) - Select(Apply(Select(tree, nme.map), List(xToWrapped)), nme.toList) - } - if (tree.tpe != null && (tree.tpe <:< listTreeType || tree.tpe <:< listListTreeType)) tree - else atPos(tree.pos)(loop(tree, n)) + private def toStats(tree: Tree): Tree = + // q"$u.build.toStats($tree)" + Apply(Select(Select(u, nme.build), nme.toStats), tree :: Nil) + + private def toList(tree: Tree, tpe: Type): Tree = + if (isListType(tpe)) tree + else Select(tree, nme.toList) + + private def mapF(tree: Tree, f: Tree => Tree): Tree = + if (f(Ident(TermName("x"))) equalsStructure Ident(TermName("x"))) tree + else { + val x: TermName = c.freshName() + // q"$tree.map { $x => ${f(Ident(x))} }" + Apply(Select(tree, nme.map), + Function(ValDef(Modifiers(PARAM), x, TypeTree(), EmptyTree) :: Nil, + f(Ident(x))) :: Nil) } - reifyIterable(tree, card) + + private object IterableType { + def unapply(tpe: Type): Option[Type] = + if (isIterableType(tpe)) Some(extractIterableTParam(tpe)) else None + } + + private object LiftedType { + def unapply(tpe: Type): Option[Tree => Tree] = + if (tpe <:< treeType) Some(t => t) + else if (isLiftableType(tpe)) Some(lifted(tpe)(_)) + else None + } + + /** Map high-cardinality splice onto an expression that eveluates as a list of given cardinality. + * + * All possible combinations of representations are given in the table below: + * + * input output for T <: Tree output for T: Liftable + * + * ..${x: Iterable[T]} x.toList x.toList.map(lift) + * ..${x: T} toStats(x) toStats(lift(x)) + * + * ...${x: Iterable[Iterable[T]]} x.toList { _.toList } x.toList.map { _.toList.map(lift) } + * ...${x: Iterable[T]} x.toList.map { toStats(_) } x.toList.map { toStats(lift(_)) } + * ...${x: T} toStats(x).map { toStats(_) } toStats(lift(x)).map { toStats(_) } + * + * For optimization purposes `x.toList` is represented as just `x` if it is statically known that + * x is not just an Iterable[T] but a List[T]. Similarly no mapping is performed if mapping function is + * known to be an identity. + */ + private def iterated(card: Cardinality, tree: Tree, tpe: Type): Tree = (card, tpe) match { + case (DotDot, tpe @ IterableType(LiftedType(lift))) => mapF(toList(tree, tpe), lift) + case (DotDot, LiftedType(lift)) => toStats(lift(tree)) + case (DotDotDot, tpe @ IterableType(inner)) => mapF(toList(tree, tpe), t => iterated(DotDot, t, inner)) + case (DotDotDot, LiftedType(lift)) => mapF(toStats(lift(tree)), toStats) + case _ => global.abort("unreachable") } } diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index 1bd9323752..fcb8734644 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -80,8 +80,20 @@ trait Parsers { self: Quasiquotes => } import treeBuilder.{global => _, unit => _, _} + def quasiquoteParam(name: Name, flags: FlagSet = NoFlags) = + ValDef(Modifiers(flags), name.toTermName, Ident(tpnme.QUASIQUOTE_PARAM), EmptyTree) + // q"def foo($x)" - override def allowTypelessParams = true + override def param(owner: Name, implicitmod: Int, caseParam: Boolean): ValDef = + if (isHole && lookingAhead { in.token == COMMA || in.token == RPAREN }) { + quasiquoteParam(ident(), implicitmod) + } else super.param(owner, implicitmod, caseParam) + + // q"($x) => ..." && q"class X { selfie => } + override def convertToParam(tree: Tree): ValDef = tree match { + case Ident(name) if isHole(name) => quasiquoteParam(name) + case _ => super.convertToParam(tree) + } // q"foo match { case $x }" override def caseClause(): CaseDef = @@ -160,17 +172,26 @@ trait Parsers { self: Quasiquotes => } } - object TermParser extends Parser { - def entryPoint = { parser => - parser.templateOrTopStatSeq() match { - case head :: Nil => Block(Nil, head) - case lst => gen.mkTreeOrBlock(lst) - } + /** Wrapper around tree parsed in q"..." quote. Needed to support ..$ splicing on top-level. */ + object Q { + def apply(tree: Tree): Block = Block(Nil, tree).updateAttachment(Q) + def unapply(tree: Tree): Option[Tree] = tree match { + case Block(Nil, contents) if tree.hasAttachment[Q.type] => Some(contents) + case _ => None } } + object TermParser extends Parser { + def entryPoint = parser => Q(gen.mkTreeOrBlock(parser.templateOrTopStatSeq())) + } + object TypeParser extends Parser { - def entryPoint = _.typ() + def entryPoint = { parser => + if (parser.in.token == EOF) + TypeTree() + else + parser.typ() + } } object CaseParser extends Parser { diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala index bdb44ad9a2..5669ec731f 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala @@ -95,7 +95,6 @@ trait Placeholders { self: Quasiquotes => case Ident(name) => name case Bind(name, Ident(nme.WILDCARD)) => name case TypeDef(_, name, List(), TypeBoundsTree(EmptyTree, EmptyTree)) => name - case ValDef(_, name, TypeTree(), EmptyTree) => name } } @@ -111,6 +110,12 @@ trait Placeholders { self: Quasiquotes => } } + object ParamPlaceholder extends HolePlaceholder { + def matching = { + case ValDef(_, name, Ident(tpnme.QUASIQUOTE_PARAM), EmptyTree) => name + } + } + object TuplePlaceholder { def unapply(tree: Tree): Option[List[Tree]] = tree match { case Apply(Ident(nme.QUASIQUOTE_TUPLE), args) => Some(args) diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index 87ab52414c..273245f7bd 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -137,6 +137,7 @@ trait Reifiers { self: Quasiquotes => case RefineStatPlaceholder(hole) => reifyRefineStat(hole) case EarlyDefPlaceholder(hole) => reifyEarlyDef(hole) case PackageStatPlaceholder(hole) => reifyPackageStat(hole) + case ParamPlaceholder(hole) => hole.tree // for enumerators are checked not during splicing but during // desugaring of the for loop in SyntacticFor & SyntacticForYield case ForEnumPlaceholder(hole) => hole.tree @@ -159,8 +160,12 @@ trait Reifiers { self: Quasiquotes => reifyBuildCall(nme.SyntacticObjectDef, mods, name, earlyDefs, parents, selfdef, body) case SyntacticNew(earlyDefs, parents, selfdef, body) => reifyBuildCall(nme.SyntacticNew, earlyDefs, parents, selfdef, body) - case SyntacticDefDef(mods, name, tparams, vparamss, tpt, rhs) => - reifyBuildCall(nme.SyntacticDefDef, mods, name, tparams, vparamss, tpt, rhs) + case SyntacticDefDef(mods, name, tparams, build.ImplicitParams(vparamss, implparams), tpt, rhs) => + if (implparams.nonEmpty) + mirrorBuildCall(nme.SyntacticDefDef, reify(mods), reify(name), reify(tparams), + reifyBuildCall(nme.ImplicitParams, vparamss, implparams), reify(tpt), reify(rhs)) + else + reifyBuildCall(nme.SyntacticDefDef, mods, name, tparams, vparamss, tpt, rhs) case SyntacticValDef(mods, name, tpt, rhs) if tree != noSelfType => reifyBuildCall(nme.SyntacticValDef, mods, name, tpt, rhs) case SyntacticVarDef(mods, name, tpt, rhs) => @@ -185,12 +190,14 @@ trait Reifiers { self: Quasiquotes => reifyBuildCall(nme.SyntacticFunction, args, body) case SyntacticIdent(name, isBackquoted) => reifyBuildCall(nme.SyntacticIdent, name, isBackquoted) - case Block(Nil, Placeholder(Hole(tree, DotDot))) => + case Q(Placeholder(Hole(tree, DotDot))) => mirrorBuildCall(nme.SyntacticBlock, tree) - case Block(Nil, other) => + case Q(other) => reifyTree(other) - case Block(stats, last) => - reifyBuildCall(nme.SyntacticBlock, stats :+ last) + // Syntactic block always matches so we have to be careful + // not to cause infinite recursion. + case block @ SyntacticBlock(stats) if block.isInstanceOf[Block] => + reifyBuildCall(nme.SyntacticBlock, stats) case Try(block, catches, finalizer) => reifyBuildCall(nme.SyntacticTry, block, catches, finalizer) case Match(selector, cases) => @@ -311,6 +318,8 @@ trait Reifiers { self: Quasiquotes => case EarlyDefPlaceholder(h @ Hole(_, DotDot)) => reifyEarlyDef(h) case PackageStatPlaceholder(h @ Hole(_, DotDot)) => reifyPackageStat(h) case ForEnumPlaceholder(Hole(tree, DotDot)) => tree + case ParamPlaceholder(Hole(tree, DotDot)) => tree + case List(ParamPlaceholder(Hole(tree, DotDotDot))) => tree case List(Placeholder(Hole(tree, DotDotDot))) => tree } { reify(_) diff --git a/src/eclipse/test-junit/.classpath b/src/eclipse/test-junit/.classpath index d028dcc21e..8a599bd8c7 100644 --- a/src/eclipse/test-junit/.classpath +++ b/src/eclipse/test-junit/.classpath @@ -7,5 +7,6 @@ <classpathentry combineaccessrules="false" kind="src" path="/scala-library"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/> + <classpathentry combineaccessrules="false" kind="src" path="/repl"/> <classpathentry kind="output" path="build-test-junit"/> </classpath> diff --git a/src/interactive/scala/tools/nsc/interactive/ContextTrees.scala b/src/interactive/scala/tools/nsc/interactive/ContextTrees.scala index 4f67a22b8f..bf718c27cc 100644 --- a/src/interactive/scala/tools/nsc/interactive/ContextTrees.scala +++ b/src/interactive/scala/tools/nsc/interactive/ContextTrees.scala @@ -64,9 +64,12 @@ trait ContextTrees { self: Global => def locateContextTree(contexts: Contexts, pos: Position): Option[ContextTree] = { if (contexts.isEmpty) None else { + // binary search on contexts, loop invar: lo <= hi, recursion metric: `hi - lo` @tailrec def loop(lo: Int, hi: Int, previousSibling: Option[ContextTree]): Option[ContextTree] = { - if (pos properlyPrecedes contexts(lo).pos) + // [SI-8239] enforce loop invariant & ensure recursion metric decreases monotonically on every recursion + if (lo > hi) previousSibling + else if (pos properlyPrecedes contexts(lo).pos) previousSibling else if (contexts(hi).pos properlyPrecedes pos) Some(contexts(hi)) @@ -76,9 +79,18 @@ trait ContextTrees { self: Global => if (midpos includes pos) Some(contexts(mid)) else if (midpos properlyPrecedes pos) + // recursion metric: (hi - ((lo + hi)/2 + 1)) < (hi - lo) + // since (hi - ((lo + hi)/2 + 1)) - (hi - lo) = lo - ((lo + hi)/2 + 1) < 0 + // since 2*lo - lo - hi - 2 = lo - hi - 2 < 0 + // since lo < hi + 2 + // can violate lo <= hi, hence the lo > hi check at the top [SI-8239] loop(mid + 1, hi, Some(contexts(mid))) - else + else if (lo != hi) // avoid looping forever (lo == hi violates the recursion metric) [SI-8239] + // recursion metric: ((lo + hi)/2) - lo < (hi - lo) + // since ((lo + hi)/2) - lo - (hi - lo) = ((lo + hi)/2) - hi < 0 + // since 2 * (((lo + hi)/2) - hi) = lo - hi < 0 since lo < hi loop(lo, mid, previousSibling) + else previousSibling } } loop(0, contexts.length - 1, None) diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index e7d87dd3fe..8a24f721d7 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -247,15 +247,17 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def removed0(key: A, hash: Int, level: Int): HashMap[A, B] = if (hash == this.hash) { val kvs1 = kvs - key - if (kvs1 eq kvs) - this - else if (kvs1.isEmpty) - HashMap.empty[A,B] - else if(kvs1.tail.isEmpty) { - val kv = kvs1.head - new HashMap1[A,B](kv._1,hash,kv._2,kv) - } else - new HashMapCollision1(hash, kvs1) + kvs1.size match { + case 0 => + HashMap.empty[A,B] + case 1 => + val kv = kvs1.head + new HashMap1(kv._1,hash,kv._2,kv) + case x if x == kvs.size => + this + case _ => + new HashMapCollision1(hash, kvs1) + } } else this override protected def filter0(p: ((A, B)) => Boolean, negate: Boolean, level: Int, buffer: Array[HashMap[A, B @uV]], offset0: Int): HashMap[A, B] = { diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 90aabc5a9a..c3728fa02a 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -325,36 +325,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] // Create a proxy for Java serialization that allows us to avoid mutation // during de-serialization. This is the Serialization Proxy Pattern. - protected final def writeReplace(): AnyRef = new SerializationProxy(this) -} - -@SerialVersionUID(1L) -private class SerializationProxy[B](@transient private var orig: List[B]) extends Serializable { - - private def writeObject(out: ObjectOutputStream) { - var xs: List[B] = orig - while (!xs.isEmpty) { - out.writeObject(xs.head) - xs = xs.tail - } - out.writeObject(ListSerializeEnd) - } - - // Java serialization calls this before readResolve during de-serialization. - // Read the whole list and store it in `orig`. - private def readObject(in: ObjectInputStream) { - val builder = List.newBuilder[B] - while (true) in.readObject match { - case ListSerializeEnd => - orig = builder.result() - return - case a => - builder += a.asInstanceOf[B] - } - } - - // Provide the result stored in `orig` for Java serialization - private def readResolve(): AnyRef = orig + protected final def writeReplace(): AnyRef = new List.SerializationProxy(this) } /** The empty list. @@ -385,8 +356,7 @@ case object Nil extends List[Nothing] { * @version 1.0, 15/07/2003 * @since 2.8 */ -final case class ::[B](private val hd: B, private[scala] var tl: List[B]) extends List[B] { - override def head : B = hd +final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] { override def tail : List[B] = tl override def isEmpty: Boolean = false } @@ -405,6 +375,35 @@ object List extends SeqFactory[List] { override def empty[A]: List[A] = Nil override def apply[A](xs: A*): List[A] = xs.toList + + @SerialVersionUID(1L) + private class SerializationProxy[A](@transient private var orig: List[A]) extends Serializable { + + private def writeObject(out: ObjectOutputStream) { + var xs: List[A] = orig + while (!xs.isEmpty) { + out.writeObject(xs.head) + xs = xs.tail + } + out.writeObject(ListSerializeEnd) + } + + // Java serialization calls this before readResolve during de-serialization. + // Read the whole list and store it in `orig`. + private def readObject(in: ObjectInputStream) { + val builder = List.newBuilder[A] + while (true) in.readObject match { + case ListSerializeEnd => + orig = builder.result() + return + case a => + builder += a.asInstanceOf[A] + } + } + + // Provide the result stored in `orig` for Java serialization + private def readResolve(): AnyRef = orig + } } /** Only used for list serialization */ diff --git a/src/library/scala/collection/immutable/ListMap.scala b/src/library/scala/collection/immutable/ListMap.scala index b2a1b1ce29..7c40e84280 100644 --- a/src/library/scala/collection/immutable/ListMap.scala +++ b/src/library/scala/collection/immutable/ListMap.scala @@ -123,12 +123,12 @@ extends AbstractMap[A, B] def hasNext = !self.isEmpty def next(): (A,B) = if (!hasNext) throw new NoSuchElementException("next on empty iterator") - else { val res = (self.key, self.value); self = self.tail; res } + else { val res = (self.key, self.value); self = self.next; res } }.toList.reverseIterator protected def key: A = throw new NoSuchElementException("empty map") protected def value: B = throw new NoSuchElementException("empty map") - override def tail: ListMap[A, B] = throw new NoSuchElementException("empty map") + protected def next: ListMap[A, B] = throw new NoSuchElementException("empty map") /** This class represents an entry in the `ListMap`. */ @@ -142,7 +142,7 @@ extends AbstractMap[A, B] override def size: Int = size0(this, 0) // to allow tail recursion and prevent stack overflows - @tailrec private def size0(cur: ListMap[A, B1], acc: Int): Int = if (cur.isEmpty) acc else size0(cur.tail, acc + 1) + @tailrec private def size0(cur: ListMap[A, B1], acc: Int): Int = if (cur.isEmpty) acc else size0(cur.next, acc + 1) /** Is this an empty map? * @@ -163,7 +163,7 @@ extends AbstractMap[A, B] @tailrec private def apply0(cur: ListMap[A, B1], k: A): B1 = if (cur.isEmpty) throw new NoSuchElementException("key not found: "+k) else if (k == cur.key) cur.value - else apply0(cur.tail, k) + else apply0(cur.next, k) /** Checks if this map maps `key` to a value and return the * value if it exists. @@ -175,7 +175,7 @@ extends AbstractMap[A, B] @tailrec private def get0(cur: ListMap[A, B1], k: A): Option[B1] = if (k == cur.key) Some(cur.value) - else if (cur.tail.nonEmpty) get0(cur.tail, k) else None + else if (cur.next.nonEmpty) get0(cur.next, k) else None /** This method allows one to create a new map with an additional mapping * from `key` to `value`. If the map contains already a mapping for `key`, @@ -196,12 +196,12 @@ extends AbstractMap[A, B] if (cur.isEmpty) acc.last else if (k == cur.key) - (cur.tail /: acc) { + (cur.next /: acc) { case (t, h) => val tt = t; new tt.Node(h.key, h.value) // SI-7459 } else - remove0(k, cur.tail, cur::acc) + remove0(k, cur.next, cur::acc) - override def tail: ListMap[A, B1] = ListMap.this + override protected def next: ListMap[A, B1] = ListMap.this } } diff --git a/src/library/scala/collection/immutable/Set.scala b/src/library/scala/collection/immutable/Set.scala index e21a8dfa8a..0fbf7942d4 100644 --- a/src/library/scala/collection/immutable/Set.scala +++ b/src/library/scala/collection/immutable/Set.scala @@ -82,6 +82,16 @@ object Set extends ImmutableSetFactory[Set] { override def foreach[U](f: A => U): Unit = { f(elem1) } + override def exists(f: A => Boolean): Boolean = { + f(elem1) + } + override def forall(f: A => Boolean): Boolean = { + f(elem1) + } + override def find(f: A => Boolean): Option[A] = { + if (f(elem1)) Some(elem1) + else None + } } /** An optimized representation for immutable sets of size 2 */ @@ -102,6 +112,17 @@ object Set extends ImmutableSetFactory[Set] { override def foreach[U](f: A => U): Unit = { f(elem1); f(elem2) } + override def exists(f: A => Boolean): Boolean = { + f(elem1) || f(elem2) + } + override def forall(f: A => Boolean): Boolean = { + f(elem1) && f(elem2) + } + override def find(f: A => Boolean): Option[A] = { + if (f(elem1)) Some(elem1) + else if (f(elem2)) Some(elem2) + else None + } } /** An optimized representation for immutable sets of size 3 */ @@ -123,6 +144,18 @@ object Set extends ImmutableSetFactory[Set] { override def foreach[U](f: A => U): Unit = { f(elem1); f(elem2); f(elem3) } + override def exists(f: A => Boolean): Boolean = { + f(elem1) || f(elem2) || f(elem3) + } + override def forall(f: A => Boolean): Boolean = { + f(elem1) && f(elem2) && f(elem3) + } + override def find(f: A => Boolean): Option[A] = { + if (f(elem1)) Some(elem1) + else if (f(elem2)) Some(elem2) + else if (f(elem3)) Some(elem3) + else None + } } /** An optimized representation for immutable sets of size 4 */ @@ -145,6 +178,19 @@ object Set extends ImmutableSetFactory[Set] { override def foreach[U](f: A => U): Unit = { f(elem1); f(elem2); f(elem3); f(elem4) } + override def exists(f: A => Boolean): Boolean = { + f(elem1) || f(elem2) || f(elem3) || f(elem4) + } + override def forall(f: A => Boolean): Boolean = { + f(elem1) && f(elem2) && f(elem3) && f(elem4) + } + override def find(f: A => Boolean): Option[A] = { + if (f(elem1)) Some(elem1) + else if (f(elem2)) Some(elem2) + else if (f(elem3)) Some(elem3) + else if (f(elem4)) Some(elem4) + else None + } } } diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index 49c3b4c3cd..60de147477 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -1108,11 +1108,15 @@ object Stream extends SeqFactory[Stream] { override def isEmpty = false override def head = hd @volatile private[this] var tlVal: Stream[A] = _ - def tailDefined: Boolean = tlVal ne null + @volatile private[this] var tlGen = tl _ + def tailDefined: Boolean = tlGen eq null override def tail: Stream[A] = { if (!tailDefined) synchronized { - if (!tailDefined) tlVal = tl + if (!tailDefined) { + tlVal = tlGen() + tlGen = null + } } tlVal diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala index 43d46cf4d0..8e1d950d00 100644 --- a/src/library/scala/collection/immutable/StringLike.scala +++ b/src/library/scala/collection/immutable/StringLike.scala @@ -131,6 +131,7 @@ self => * end characters, i.e. apply `.stripLineEnd` to all lines * returned by `linesWithSeparators`. */ + @deprecated("Use `lines` instead.","2.11.0") def linesIterator: Iterator[String] = linesWithSeparators map (line => new WrappedString(line).stripLineEnd) diff --git a/src/library/scala/collection/mutable/AnyRefMap.scala b/src/library/scala/collection/mutable/AnyRefMap.scala index df74bb5187..29c92a111c 100644 --- a/src/library/scala/collection/mutable/AnyRefMap.scala +++ b/src/library/scala/collection/mutable/AnyRefMap.scala @@ -129,9 +129,20 @@ extends AbstractMap[K, V] override def getOrElseUpdate(key: K, defaultValue: => V): V = { val h = hashOf(key) - val i = seekEntryOrOpen(h, key) + var i = seekEntryOrOpen(h, key) if (i < 0) { - val value = defaultValue + // It is possible that the default value computation was side-effecting + // Our hash table may have resized or even contain what we want now + // (but if it does, we'll replace it) + val value = { + val oh = _hashes + val ans = defaultValue + if (oh ne _hashes) { + i = seekEntryOrOpen(h, key) + if (i >= 0) _size -= 1 + } + ans + } _size += 1 val j = i & IndexMask _hashes(j) = h diff --git a/src/library/scala/collection/mutable/LongMap.scala b/src/library/scala/collection/mutable/LongMap.scala index 81c381279f..984ae6f7cc 100644 --- a/src/library/scala/collection/mutable/LongMap.scala +++ b/src/library/scala/collection/mutable/LongMap.scala @@ -160,9 +160,20 @@ extends AbstractMap[Long, V] else minValue.asInstanceOf[V] } else { - val i = seekEntryOrOpen(key) + var i = seekEntryOrOpen(key) if (i < 0) { - val value = defaultValue + // It is possible that the default value computation was side-effecting + // Our hash table may have resized or even contain what we want now + // (but if it does, we'll replace it) + val value = { + val ok = _keys + val ans = defaultValue + if (ok ne _keys) { + i = seekEntryOrOpen(key) + if (i >= 0) _size -= 1 + } + ans + } _size += 1 val j = i & IndexMask _keys(j) = key diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index d3c5a6b019..a55432fd71 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -14,9 +14,45 @@ import scala.annotation.implicitNotFound import scala.util.Try /** - * An `ExecutionContext` is an abstraction over an entity that can execute program logic. + * An `ExecutionContext` can execute program logic, typically but not + * necessarily on a thread pool. + * + * APIs such as `Future.onComplete` require you to provide a callback + * and an implicit `ExecutionContext`. The implicit `ExecutionContext` + * will be used to execute the callback. + * + * It is possible to simply import + * `scala.concurrent.ExecutionContext.Implicits.global` to obtain an + * implicit `ExecutionContext`. This global context is a reasonable + * default thread pool. + * + * However, application developers should carefully consider where they + * want to set policy; ideally, one place per application (or per + * logically-related section of code) will make a decision about + * which `ExecutionContext` to use. That is, you might want to avoid + * hardcoding `scala.concurrent.ExecutionContext.Implicits.global` all + * over the place in your code. + * One approach is to add `(implicit ec: ExecutionContext)` + * to methods which need an `ExecutionContext`. Then import a specific + * context in one place for the entire application or module, + * passing it implicitly to individual methods. + * + * A custom `ExecutionContext` may be appropriate to execute code + * which blocks on IO or performs long-running computations. + * `ExecutionContext.fromExecutorService` and `ExecutionContext.fromExecutor` + * are good ways to create a custom `ExecutionContext`. + * + * The intent of `ExecutionContext` is to lexically scope code execution. + * That is, each method, class, file, package, or application determines + * how to run its own code. This avoids issues such as running + * application callbacks on a thread pool belonging to a networking library. + * The size of a networking library's thread pool can be safely configured, + * knowing that only that library's network operations will be affected. + * Application callback execution can be configured separately. */ -@implicitNotFound("Cannot find an implicit ExecutionContext, either import scala.concurrent.ExecutionContext.Implicits.global or use a custom one") +@implicitNotFound("""Cannot find an implicit ExecutionContext. You might pass +an (implicit ec: ExecutionContext) parameter to your method +or import scala.concurrent.ExecutionContext.Implicits.global.""") trait ExecutionContext { /** Runs a block of code on this execution context. diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index d271c4cdeb..4ed0687334 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -494,9 +494,9 @@ object Future { /** Simple version of `Future.traverse`. Transforms a `TraversableOnce[Future[A]]` into a `Future[TraversableOnce[A]]`. * Useful for reducing many `Future`s into a single `Future`. */ - def sequence[A, M[_] <: TraversableOnce[_]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = { + def sequence[A, M[X] <: TraversableOnce[X]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = { in.foldLeft(successful(cbf(in))) { - (fr, fa) => for (r <- fr; a <- fa.asInstanceOf[Future[A]]) yield (r += a) + (fr, fa) => for (r <- fr; a <- fa) yield (r += a) } map (_.result()) } @@ -569,9 +569,9 @@ object Future { * val myFutureList = Future.traverse(myList)(x => Future(myFunc(x))) * }}} */ - def traverse[A, B, M[_] <: TraversableOnce[_]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] = + def traverse[A, B, M[X] <: TraversableOnce[X]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] = in.foldLeft(successful(cbf(in))) { (fr, a) => - val fb = fn(a.asInstanceOf[A]) + val fb = fn(a) for (r <- fr; b <- fb) yield (r += b) }.map(_.result()) diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala index 86132bb876..b70426a145 100644 --- a/src/library/scala/util/matching/Regex.scala +++ b/src/library/scala/util/matching/Regex.scala @@ -67,7 +67,21 @@ import java.util.regex.{ Pattern, Matcher } * Regex, such as `findFirstIn` or `findAllIn`, or using it as an extractor in a * pattern match. * - * Note, however, that when Regex is used as an extractor in a pattern match, it + * Note that, when calling `findAllIn`, the resulting [[scala.util.matching.Regex.MatchIterator]] + * needs to be initialized (by calling `hasNext` or `next()`, or causing these to be + * called) before information about a match can be retrieved: + * + * {{{ + * val msg = "I love Scala" + * + * // val start = " ".r.findAllIn(msg).start // throws an IllegalStateException + * + * val matches = " ".r.findAllIn(msg) + * matches.hasNext // initializes the matcher + * val start = matches.start + * }}} + * + * When Regex is used as an extractor in a pattern match, note that it * only succeeds if the whole text can be matched. For this reason, one usually * calls a method to find the matching substrings, and then use it as an extractor * to break match into subgroups. @@ -267,6 +281,10 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends * that can be queried for data such as the text that precedes the * match, subgroups, etc. * + * Attempting to retrieve information about a match before initializing + * the iterator can result in [[java.lang.IllegalStateException]]s. See + * [[scala.util.matching.Regex.MatchIterator]] for details. + * * @param source The text to match against. * @return A [[scala.util.matching.Regex.MatchIterator]] of all matches. * @example {{{for (words <- """\w+""".r findAllIn "A simple example.") yield words}}} @@ -476,15 +494,7 @@ trait UnanchoredRegex extends Regex { } /** This object defines inner classes that describe - * regex matches and helper objects. The class hierarchy - * is as follows: - * - * {{{ - * MatchData - * / \ - * MatchIterator Match - * }}} - * + * regex matches and helper objects. */ object Regex { @@ -634,7 +644,14 @@ object Regex { def unapplySeq(m: Match): Option[Seq[String]] = if (m.groupCount > 0) Some(1 to m.groupCount map m.group) else None } - /** A class to step through a sequence of regex matches + /** A class to step through a sequence of regex matches. + * + * All methods inherited from [[scala.util.matching.Regex.MatchData]] will throw + * an [[java.lang.IllegalStateException]] until the matcher is initialized by + * calling `hasNext` or `next()` or causing these methods to be called, such as + * by invoking `toString` or iterating through the iterator's elements. + * + * @see [[java.util.regex.Matcher]] */ class MatchIterator(val source: CharSequence, val regex: Regex, val groupNames: Seq[String]) extends AbstractIterator[String] with Iterator[String] with MatchData { self => diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 10c2def72a..3bcf751ace 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -72,6 +72,8 @@ private[reflect] trait BuildUtils { self: Universe => def setSymbol[T <: Tree](tree: T, sym: Symbol): T + def toStats(tree: Tree): List[Tree] + def mkAnnotation(tree: Tree): Tree def mkAnnotation(trees: List[Tree]): List[Tree] @@ -94,6 +96,13 @@ private[reflect] trait BuildUtils { self: Universe => def freshTypeName(prefix: String): TypeName + val ImplicitParams: ImplicitParamsExtractor + + trait ImplicitParamsExtractor { + def apply(paramss: List[List[ValDef]], implparams: List[ValDef]): List[List[ValDef]] + def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])] + } + val ScalaDot: ScalaDotExtractor trait ScalaDotExtractor { @@ -126,8 +135,8 @@ private[reflect] trait BuildUtils { self: Universe => trait SyntacticClassDefExtractor { def apply(mods: Modifiers, name: TypeName, tparams: List[Tree], - constrMods: Modifiers, vparamss: List[List[Tree]], earlyDefs: List[Tree], - parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef + constrMods: Modifiers, vparamss: List[List[Tree]], + earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], Modifiers, List[List[ValDef]], List[Tree], List[Tree], ValDef, List[Tree])] } @@ -145,7 +154,7 @@ private[reflect] trait BuildUtils { self: Universe => trait SyntacticObjectDefExtractor { def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfType: Tree, body: List[Tree]): Tree + parents: List[Tree], selfType: Tree, body: List[Tree]): ModuleDef def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])] } @@ -153,7 +162,7 @@ private[reflect] trait BuildUtils { self: Universe => trait SyntacticPackageObjectDefExtractor { def apply(name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfType: Tree, body: List[Tree]): Tree + parents: List[Tree], selfType: Tree, body: List[Tree]): PackageDef def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] } @@ -197,9 +206,10 @@ private[reflect] trait BuildUtils { self: Universe => val SyntacticDefDef: SyntacticDefDefExtractor trait SyntacticDefDefExtractor { - def apply(mods: Modifiers, name: TermName, tparams: List[Tree], vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef + def apply(mods: Modifiers, name: TermName, tparams: List[Tree], + vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef - def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[List[ValDef]], Tree, Tree)] + def unapply(tree: Tree): Option[(Modifiers, TermName, List[TypeDef], List[List[ValDef]], Tree, Tree)] } val SyntacticValDef: SyntacticValDefExtractor diff --git a/src/reflect/scala/reflect/api/StandardDefinitions.scala b/src/reflect/scala/reflect/api/StandardDefinitions.scala index e255d305f7..1a8885e6b5 100644 --- a/src/reflect/scala/reflect/api/StandardDefinitions.scala +++ b/src/reflect/scala/reflect/api/StandardDefinitions.scala @@ -214,6 +214,14 @@ trait StandardDefinitions { /** The module symbol of module `scala.Some`. */ def SomeModule: ModuleSymbol + /** Function-like api that lets you acess symbol + * of the definition with given arity and also look + * through all known symbols via `seq`. + */ + abstract class VarArityClassApi extends (Int => Symbol) { + def seq: Seq[ClassSymbol] + } + /** Function-like object that maps arity to symbols for classes `scala.ProductX`. * - 0th element is `Unit` * - 1st element is `Product1` @@ -222,7 +230,7 @@ trait StandardDefinitions { * - 23nd element is `NoSymbol` * - ... */ - def ProductClass: Int => Symbol + def ProductClass: VarArityClassApi /** Function-like object that maps arity to symbols for classes `scala.FunctionX`. * - 0th element is `Function0` @@ -232,17 +240,17 @@ trait StandardDefinitions { * - 23nd element is `NoSymbol` * - ... */ - def FunctionClass: Int => Symbol + def FunctionClass: VarArityClassApi /** Function-like object that maps arity to symbols for classes `scala.TupleX`. * - 0th element is `NoSymbol` - * - 1st element is `Product1` + * - 1st element is `Tuple1` * - ... - * - 22nd element is `Product22` + * - 22nd element is `Tuple22` * - 23nd element is `NoSymbol` * - ... */ - def TupleClass: Int => Symbol + def TupleClass: VarArityClassApi /** Contains Scala primitive value classes: * - Byte diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala index 1c9b77581a..85a8ee0185 100644 --- a/src/reflect/scala/reflect/api/Universe.scala +++ b/src/reflect/scala/reflect/api/Universe.scala @@ -81,14 +81,14 @@ abstract class Universe extends Symbols with Liftables with Quasiquotes { - /** Use `refiy` to produce the abstract syntax tree representing a given Scala expression. + /** Use `reify` to produce the abstract syntax tree representing a given Scala expression. * * For example: * * {{{ - * val five = reify{ 5 } // Literal(Constant(5)) - * reify{ 2 + 4 } // Apply( Select( Literal(Constant(2)), newTermName("\$plus")), List( Literal(Constant(4)) ) ) - * reify{ five.splice + 4 } // Apply( Select( Literal(Constant(5)), newTermName("\$plus")), List( Literal(Constant(4)) ) ) + * val five = reify{ 5 } // Literal(Constant(5)) + * reify{ 5.toString } // Apply(Select(Literal(Constant(5)), TermName("toString")), List()) + * reify{ five.splice.toString } // Apply(Select(five, TermName("toString")), List()) * }}} * * The produced tree is path dependent on the Universe `reify` was called from. diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index 4fde57ed02..d634034fe9 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -48,7 +48,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => /** Tests for, get, or remove an annotation */ def hasAnnotation(cls: Symbol): Boolean = //OPT inlined from exists to save on #closures; was: annotations exists (_ matches cls) - dropOtherAnnotations(annotations, cls).nonEmpty + dropOtherAnnotations(annotations, cls) ne Nil def getAnnotation(cls: Symbol): Option[AnnotationInfo] = //OPT inlined from exists to save on #closures; was: annotations find (_ matches cls) diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 9b19dc11cb..6106339324 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -61,6 +61,8 @@ trait BuildUtils { self: SymbolTable => def setSymbol[T <: Tree](tree: T, sym: Symbol): T = { tree.setSymbol(sym); tree } + def toStats(tree: Tree): List[Tree] = SyntacticBlock.unapply(tree).get + def mkAnnotation(tree: Tree): Tree = tree match { case SyntacticNew(Nil, SyntacticApplied(SyntacticTypeApplied(_, _), _) :: Nil, noSelfType, Nil) => tree @@ -71,18 +73,25 @@ trait BuildUtils { self: SymbolTable => def mkAnnotation(trees: List[Tree]): List[Tree] = trees.map(mkAnnotation) - def mkVparamss(argss: List[List[Tree]]): List[List[ValDef]] = argss.map(_.map(mkParam)) + def mkParam(argss: List[List[Tree]], extraFlags: FlagSet = NoFlags): List[List[ValDef]] = + argss.map { args => args.map { mkParam(_, extraFlags) } } - def mkParam(tree: Tree): ValDef = tree match { + def mkParam(tree: Tree, extraFlags: FlagSet): ValDef = tree match { + case Typed(Ident(name: TermName), tpt) => + mkParam(ValDef(NoMods, name, tpt, EmptyTree), extraFlags) case vd: ValDef => - var newmods = (vd.mods | PARAM) & (~DEFERRED) + var newmods = vd.mods & (~DEFERRED) if (vd.rhs.nonEmpty) newmods |= DEFAULTPARAM - copyValDef(vd)(mods = newmods) + copyValDef(vd)(mods = newmods | extraFlags) case _ => - throw new IllegalArgumentException(s"$tree is not valid represenation of function parameter, " + + throw new IllegalArgumentException(s"$tree is not valid represenation of a parameter, " + """consider reformatting it into q"val $name: $T = $default" shape""") } + def mkImplicitParam(args: List[Tree]): List[ValDef] = args.map(mkImplicitParam) + + def mkImplicitParam(tree: Tree): ValDef = mkParam(tree, IMPLICIT | PARAM) + def mkTparams(tparams: List[Tree]): List[TypeDef] = tparams.map { case td: TypeDef => copyTypeDef(td)(mods = (td.mods | PARAM) & (~DEFERRED)) @@ -140,6 +149,16 @@ trait BuildUtils { self: SymbolTable => protected implicit def fresh: FreshNameCreator = self.currentFreshNameCreator + object ImplicitParams extends ImplicitParamsExtractor { + def apply(paramss: List[List[ValDef]], implparams: List[ValDef]): List[List[ValDef]] = + if (implparams.nonEmpty) paramss :+ mkImplicitParam(implparams) else paramss + + def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])] = vparamss match { + case init :+ (last @ (initlast :: _)) if initlast.mods.isImplicit => Some((init, last)) + case _ => Some((vparamss, Nil)) + } + } + object FlagsRepr extends FlagsReprExtractor { def apply(bits: Long): FlagSet = bits def unapply(flags: Long): Some[Long] = Some(flags) @@ -239,14 +258,10 @@ trait BuildUtils { self: SymbolTable => object SyntacticClassDef extends SyntacticClassDefExtractor { def apply(mods: Modifiers, name: TypeName, tparams: List[Tree], - constrMods: Modifiers, vparamss: List[List[Tree]], earlyDefs: List[Tree], - parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = { + constrMods: Modifiers, vparamss: List[List[Tree]], + earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = { val extraFlags = PARAMACCESSOR | (if (mods.isCase) CASEACCESSOR else 0L) - val vparamss0 = vparamss.map { _.map { - case vd: ValDef => copyValDef(vd)(mods = (vd.mods | extraFlags) & (~DEFERRED)) - case tree => throw new IllegalArgumentException(s"$tree is not valid representation of class parameter, " + - """consider reformatting it into q"val $name: $T = $default" shape""") - } } + val vparamss0 = mkParam(vparamss, extraFlags) val tparams0 = mkTparams(tparams) val parents0 = gen.mkParents(mods, if (mods.isCase) parents.filter { @@ -289,7 +304,7 @@ trait BuildUtils { self: SymbolTable => object SyntacticObjectDef extends SyntacticObjectDefExtractor { def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfType: Tree, body: List[Tree]) = + parents: List[Tree], selfType: Tree, body: List[Tree]): ModuleDef = ModuleDef(mods, name, gen.mkTemplate(parents, mkSelfType(selfType), NoMods, Nil, earlyDefs ::: body)) def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match { @@ -302,7 +317,7 @@ trait BuildUtils { self: SymbolTable => object SyntacticPackageObjectDef extends SyntacticPackageObjectDefExtractor { def apply(name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfType: Tree, body: List[Tree]): Tree = + parents: List[Tree], selfType: Tree, body: List[Tree]): PackageDef = gen.mkPackageObject(SyntacticObjectDef(NoMods, name, earlyDefs, parents, selfType, body)) def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match { @@ -381,19 +396,47 @@ trait BuildUtils { self: SymbolTable => } } + object SyntheticUnit { + def unapply(tree: Tree): Boolean = tree match { + case Literal(Constant(())) if tree.hasAttachment[SyntheticUnitAttachment.type] => true + case _ => false + } + } + + /** Syntactic combinator that abstracts over Block tree. + * + * Apart from providing a more straightforward api that exposes + * block as a list of elements rather than (stats, expr) pair + * it also: + * + * 1. Treats of q"" (empty tree) as zero-element block. + * + * 2. Strips trailing synthetic units which are inserted by the + * compiler if the block ends with a definition rather + * than an expression. + * + * 3. Matches non-block term trees and recognizes them as + * single-element blocks for sake of consistency with + * compiler's default to treat single-element blocks with + * expressions as just expressions. + */ object SyntacticBlock extends SyntacticBlockExtractor { - def apply(stats: List[Tree]): Tree = gen.mkBlock(stats) + def apply(stats: List[Tree]): Tree = + if (stats.isEmpty) EmptyTree + else gen.mkBlock(stats) def unapply(tree: Tree): Option[List[Tree]] = tree match { - case self.Block(stats, expr) => Some(stats :+ expr) - case _ if tree.isTerm => Some(tree :: Nil) - case _ => None + case self.Block(stats, SyntheticUnit()) => Some(stats) + case self.Block(stats, expr) => Some(stats :+ expr) + case EmptyTree => Some(Nil) + case _ if tree.isTerm => Some(tree :: Nil) + case _ => None } } object SyntacticFunction extends SyntacticFunctionExtractor { def apply(params: List[Tree], body: Tree): Tree = { - val params0 :: Nil = mkVparamss(params :: Nil) + val params0 :: Nil = mkParam(params :: Nil, PARAM) require(params0.forall { _.rhs.isEmpty }, "anonymous functions don't support parameters with default values") Function(params0, body) } @@ -420,11 +463,15 @@ trait BuildUtils { self: SymbolTable => } object SyntacticDefDef extends SyntacticDefDefExtractor { - def apply(mods: Modifiers, name: TermName, tparams: List[Tree], vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef = - DefDef(mods, name, mkTparams(tparams), mkVparamss(vparamss), tpt, rhs) + def apply(mods: Modifiers, name: TermName, tparams: List[Tree], + vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef = { + val vparamss0 = mkParam(vparamss, PARAM) + DefDef(mods, name, mkTparams(tparams), vparamss0, tpt, rhs) + } - def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[List[ValDef]], Tree, Tree)] = tree match { - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => Some((mods, name, tparams, vparamss, tpt, rhs)) + def unapply(tree: Tree): Option[(Modifiers, TermName, List[TypeDef], List[List[ValDef]], Tree, Tree)] = tree match { + case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + Some((mods, name, tparams, vparamss, tpt, rhs)) case _ => None } } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index c2939e69b5..4d24f0b219 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -522,7 +522,7 @@ trait Definitions extends api.StandardDefinitions { def hasJavaMainMethod(sym: Symbol): Boolean = (sym.tpe member nme.main).alternatives exists isJavaMainMethod - class VarArityClass(name: String, maxArity: Int, countFrom: Int = 0, init: Option[ClassSymbol] = None) extends (Int => Symbol) { + class VarArityClass(name: String, maxArity: Int, countFrom: Int = 0, init: Option[ClassSymbol] = None) extends VarArityClassApi { private val offset = countFrom - init.size private def isDefinedAt(i: Int) = i < seq.length + offset && i >= offset val seq: IndexedSeq[ClassSymbol] = (init ++: countFrom.to(maxArity).map { i => getRequiredClass("scala." + name + i) }).toVector @@ -625,6 +625,7 @@ trait Definitions extends api.StandardDefinitions { def isBlackboxMacroBundleType(tp: Type) = isMacroBundleType(tp) && (macroBundleParamInfo(tp) <:< BlackboxContextClass.tpe) + def isListType(tp: Type) = tp <:< classExistentialType(ListClass) def isIterableType(tp: Type) = tp <:< classExistentialType(IterableClass) // These "direct" calls perform no dealiasing. They are most needed when diff --git a/src/reflect/scala/reflect/internal/FreshNames.scala b/src/reflect/scala/reflect/internal/FreshNames.scala index bb488aa2a8..1de8d425ad 100644 --- a/src/reflect/scala/reflect/internal/FreshNames.scala +++ b/src/reflect/scala/reflect/internal/FreshNames.scala @@ -9,6 +9,10 @@ package internal import scala.reflect.internal.util.FreshNameCreator trait FreshNames { self: Names => + // SI-6879 Keeps track of counters that are supposed to be globally unique + // as opposed to traditional freshers that are unique to compilation units. + val globalFreshNameCreator = new FreshNameCreator + // default fresh name creator used to abstract over currentUnit.fresh and runtime fresh name creator def currentFreshNameCreator: FreshNameCreator diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index 4075653674..73ce59feb2 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -345,6 +345,13 @@ trait Names extends api.Names { i += 1 i == prefix.length } + final def startsWith(prefix: String, start: Int): Boolean = { + var i = 0 + while (i < prefix.length && start + i < len && + chrs(index + start + i) == prefix.charAt(i)) + i += 1 + i == prefix.length + } /** Does this name end with suffix? */ final def endsWith(suffix: Name): Boolean = endsWith(suffix, len) @@ -357,6 +364,13 @@ trait Names extends api.Names { i += 1 i > suffix.length } + final def endsWith(suffix: String, end: Int): Boolean = { + var i = 1 + while (i <= suffix.length && i <= end && + chrs(index + end - i) == suffix.charAt(suffix.length - i)) + i += 1 + i > suffix.length + } final def containsName(subname: String): Boolean = containsName(newTermName(subname)) final def containsName(subname: Name): Boolean = { @@ -382,9 +396,9 @@ trait Names extends api.Names { final def startChar: Char = this charAt 0 final def endChar: Char = this charAt len - 1 final def startsWith(char: Char): Boolean = len > 0 && startChar == char - final def startsWith(name: String): Boolean = startsWith(newTermName(name)) + final def startsWith(name: String): Boolean = startsWith(name, 0) final def endsWith(char: Char): Boolean = len > 0 && endChar == char - final def endsWith(name: String): Boolean = endsWith(newTermName(name)) + final def endsWith(name: String): Boolean = endsWith(name, len) /** Rewrite the confusing failure indication via result == length to * the normal failure indication via result == -1. @@ -443,9 +457,10 @@ trait Names extends api.Names { } /** TODO - find some efficiency. */ - def append(ch: Char) = newName("" + this + ch) - def append(suffix: String) = newName("" + this + suffix) - def append(suffix: Name) = newName("" + this + suffix) + def append(ch: Char) = newName(toString + ch) + def append(suffix: String) = newName(toString + suffix) + def append(suffix: Name) = newName(toString + suffix) + def append(separator: Char, suffix: Name) = newName(toString + separator + suffix) def prepend(prefix: String) = newName("" + prefix + this) def decodedName: ThisNameType = newName(decode) @@ -463,7 +478,7 @@ trait Names extends api.Names { */ final class NameOps[T <: Name](name: T) { import NameTransformer._ - def stripSuffix(suffix: String): T = stripSuffix(suffix: TermName) + def stripSuffix(suffix: String): T = if (name endsWith suffix) dropRight(suffix.length) else name // OPT avoid creating a Name with `suffix` def stripSuffix(suffix: Name): T = if (name endsWith suffix) dropRight(suffix.length) else name def take(n: Int): T = name.subName(0, n).asInstanceOf[T] def drop(n: Int): T = name.subName(n, name.length).asInstanceOf[T] @@ -500,21 +515,21 @@ trait Names extends api.Names { /** TermName_S and TypeName_S have fields containing the string version of the name. * TermName_R and TypeName_R recreate it each time toString is called. */ - private class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) { + private final class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) { protected def createCompanionName(h: Int): TypeName = new TypeName_S(index, len, h, toString) override def newName(str: String): TermName = newTermNameCached(str) } - private class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) { + private final class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) { protected def createCompanionName(h: Int): TermName = new TermName_S(index, len, h, toString) override def newName(str: String): TypeName = newTypeNameCached(str) } - private class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) { + private final class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) { protected def createCompanionName(h: Int): TypeName = new TypeName_R(index, len, h) override def toString = new String(chrs, index, len) } - private class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) { + private final class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) { protected def createCompanionName(h: Int): TermName = new TermName_R(index, len, h) override def toString = new String(chrs, index, len) } diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala index 09fd996f39..139a79ffe1 100644 --- a/src/reflect/scala/reflect/internal/StdAttachments.scala +++ b/src/reflect/scala/reflect/internal/StdAttachments.scala @@ -36,6 +36,10 @@ trait StdAttachments { */ case object ForAttachment extends PlainAttachment + /** Identifies unit constants which were inserted by the compiler (e.g. gen.mkBlock) + */ + case object SyntheticUnitAttachment extends PlainAttachment + /** Untyped list of subpatterns attached to selector dummy. */ case class SubpatternsAttachment(patterns: List[Tree]) } diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index ed3e7dbc4c..28d799ea0c 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -53,14 +53,17 @@ trait StdNames { * * We obtain the formula: * - * FileNameLength = 2*(MaxNameLength / 4) + 2.marker.length + 32 + 6 + * FileNameLength = 2*(MaxNameLength / 4) + 2.marker.length + 32 + suffixLength * - * (+6 for ".class"). MaxNameLength can therefore be computed as follows: + * (+suffixLength for ".class" and potential module class suffix that is added *after* this transform). + * + * MaxNameLength can therefore be computed as follows: */ val marker = "$$$$" + val maxSuffixLength = "$.class".length + 1 // potential module class suffix and file extension val MaxNameLength = math.min( - settings.maxClassfileName.value - 6, - 2 * (settings.maxClassfileName.value - 6 - 2*marker.length - 32) + settings.maxClassfileName.value - maxSuffixLength, + 2 * (settings.maxClassfileName.value - maxSuffixLength - 2*marker.length - 32) ) def toMD5(s: String, edge: Int): String = { val prefix = s take edge @@ -250,12 +253,13 @@ trait StdNames { final val Quasiquote: NameType = "Quasiquote" // quasiquote-specific names - final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$" - final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$" - final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$" - final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$" final val QUASIQUOTE_EARLY_DEF: NameType = "$quasiquote$early$def$" + final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$" + final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$" final val QUASIQUOTE_PACKAGE_STAT: NameType = "$quasiquote$package$stat$" + final val QUASIQUOTE_PARAM: NameType = "$quasiquote$param$" + final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$" + final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$" // Annotation simple names, used in Namer final val BeanPropertyAnnot: NameType = "BeanProperty" @@ -305,6 +309,8 @@ trait StdNames { val PROTECTED_SET_PREFIX = PROTECTED_PREFIX + "set" val SUPER_PREFIX_STRING = "super$" val WHILE_PREFIX = "while$" + val FRESH_PREFIX = "fresh" + val FRESH_SUFFIX = "macro$" // uses a keyword to avoid collisions with mangled names // Compiler internal names val ANYname: NameType = "<anyname>" @@ -575,6 +581,7 @@ trait StdNames { val Flag : NameType = "Flag" val FlagsRepr: NameType = "FlagsRepr" val Ident: NameType = "Ident" + val ImplicitParams: NameType = "ImplicitParams" val Import: NameType = "Import" val Literal: NameType = "Literal" val LiteralAnnotArg: NameType = "LiteralAnnotArg" @@ -703,9 +710,9 @@ trait StdNames { val materializeTypeTag: NameType = "materializeTypeTag" val moduleClass : NameType = "moduleClass" val mkAnnotation: NameType = "mkAnnotation" - val mkRefineStat: NameType = "mkRefineStat" val mkEarlyDef: NameType = "mkEarlyDef" val mkPackageStat: NameType = "mkPackageStat" + val mkRefineStat: NameType = "mkRefineStat" val ne: NameType = "ne" val newArray: NameType = "newArray" val newFreeTerm: NameType = "newFreeTerm" @@ -750,6 +757,7 @@ trait StdNames { val toArray: NameType = "toArray" val toList: NameType = "toList" val toObjectArray : NameType = "toObjectArray" + val toStats: NameType = "toStats" val TopScope: NameType = "TopScope" val toString_ : NameType = "toString" val toTypeConstructor: NameType = "toTypeConstructor" diff --git a/src/reflect/scala/reflect/internal/SymbolPairs.scala b/src/reflect/scala/reflect/internal/SymbolPairs.scala index b538648b36..c088e8f57c 100644 --- a/src/reflect/scala/reflect/internal/SymbolPairs.scala +++ b/src/reflect/scala/reflect/internal/SymbolPairs.scala @@ -125,7 +125,7 @@ abstract class SymbolPairs { * considered as a (lo, high) pair? Types always match. Term symbols * match if their member types relative to `self` match. */ - protected def matches(sym1: Symbol, sym2: Symbol): Boolean + protected def matches(lo: Symbol, high: Symbol): Boolean /** The parents and base classes of `base`. Can be refined in subclasses. */ diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index f49ddaf6ca..b8cd1e86d3 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -1102,7 +1102,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def fullNameInternal(separator: Char): Name = ( if (isRoot || isRootPackage || this == NoSymbol) name else if (owner.isEffectiveRoot) name - else ((effectiveOwner.enclClass.fullNameAsName(separator) append separator): Name) append name + else effectiveOwner.enclClass.fullNameAsName(separator) append (separator, name) ) def fullNameAsName(separator: Char): Name = fullNameInternal(separator).dropLocal @@ -3404,8 +3404,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => * @return the new list of info-adjusted symbols */ def deriveSymbols(syms: List[Symbol], symFn: Symbol => Symbol): List[Symbol] = { - val syms1 = syms map symFn - syms1 map (_ substInfo (syms, syms1)) + val syms1 = mapList(syms)(symFn) + mapList(syms1)(_ substInfo (syms, syms1)) } /** Derives a new Type by first deriving new symbols as in deriveSymbols, @@ -3445,9 +3445,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => * @return the newly created, info-adjusted symbols */ def cloneSymbolsAndModify(syms: List[Symbol], infoFn: Type => Type): List[Symbol] = - cloneSymbols(syms) map (_ modifyInfo infoFn) + mapList(cloneSymbols(syms))(_ modifyInfo infoFn) def cloneSymbolsAtOwnerAndModify(syms: List[Symbol], owner: Symbol, infoFn: Type => Type): List[Symbol] = - cloneSymbolsAtOwner(syms, owner) map (_ modifyInfo infoFn) + mapList(cloneSymbolsAtOwner(syms, owner))(_ modifyInfo infoFn) /** Functions which perform the standard clone/substituting on the given symbols and type, * then call the creator function with the new symbols and type as arguments. diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index b16cbd8325..29fdba2781 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -49,10 +49,10 @@ abstract class TreeGen extends macros.TreeBuilder { mkMethodCall(Select(receiver, method), targs, args) def mkMethodCall(target: Tree, targs: List[Type], args: List[Tree]): Tree = - Apply(mkTypeApply(target, targs map TypeTree), args) + Apply(mkTypeApply(target, mapList(targs)(TypeTree)), args) def mkNullaryCall(method: Symbol, targs: List[Type]): Tree = - mkTypeApply(mkAttributedRef(method), targs map TypeTree) + mkTypeApply(mkAttributedRef(method), mapList(targs)(TypeTree)) /** Builds a reference to value whose type is given stable prefix. * The type must be suitable for this. For example, it @@ -281,7 +281,7 @@ abstract class TreeGen extends macros.TreeBuilder { case tree :: Nil if flattenUnary => tree case _ => - Apply(scalaDot(TupleClass(elems.length).companionModule.name), elems) + Apply(scalaDot(TupleClass(elems.length).name.toTermName), elems) } def mkTupleType(elems: List[Tree], flattenUnary: Boolean = true): Tree = elems match { @@ -342,7 +342,7 @@ abstract class TreeGen extends macros.TreeBuilder { } param } - + val (edefs, rest) = body span treeInfo.isEarlyDef val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef val gvdefs = evdefs map { @@ -381,11 +381,11 @@ abstract class TreeGen extends macros.TreeBuilder { } constr foreach (ensureNonOverlapping(_, parents ::: gvdefs, focus = false)) // Field definitions for the class - remove defaults. - + val fieldDefs = vparamss.flatten map (vd => { val field = copyValDef(vd)(mods = vd.mods &~ DEFAULTPARAM, rhs = EmptyTree) // Prevent overlapping of `field` end's position with default argument's start position. - // This is needed for `Positions.Locator(pos).traverse` to return the correct tree when + // This is needed for `Positions.Locator(pos).traverse` to return the correct tree when // the `pos` is a point position with all its values equal to `vd.rhs.pos.start`. if(field.pos.isRange && vd.rhs.pos.isRange) field.pos = field.pos.withEnd(vd.rhs.pos.start - 1) field @@ -444,13 +444,23 @@ abstract class TreeGen extends macros.TreeBuilder { def mkFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = AppliedTypeTree(rootScalaDot(newTypeName("Function" + argtpes.length)), argtpes ::: List(restpe)) + /** Create a literal unit tree that is inserted by the compiler but not + * written by end user. It's important to distinguish the two so that + * quasiquotes can strip synthetic ones away. + */ + def mkSyntheticUnit() = Literal(Constant(())).updateAttachment(SyntheticUnitAttachment) + /** Create block of statements `stats` */ def mkBlock(stats: List[Tree]): Tree = if (stats.isEmpty) Literal(Constant(())) - else if (!stats.last.isTerm) Block(stats, Literal(Constant(()))) + else if (!stats.last.isTerm) Block(stats, mkSyntheticUnit()) else if (stats.length == 1) stats.head else Block(stats.init, stats.last) + /** Create a block that wraps multiple statements but don't + * do any wrapping if there is just one statement. Used by + * quasiquotes, macro c.parse api and toolbox. + */ def mkTreeOrBlock(stats: List[Tree]) = stats match { case Nil => EmptyTree case head :: Nil => head diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 497a7c91b1..7bab15b0f4 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -284,17 +284,17 @@ abstract class TreeInfo { /** Is tree a self constructor call this(...)? I.e. a call to a constructor of the * same object? */ - def isSelfConstrCall(tree: Tree): Boolean = tree match { - case Applied(Ident(nme.CONSTRUCTOR), _, _) => true - case Applied(Select(This(_), nme.CONSTRUCTOR), _, _) => true - case _ => false + def isSelfConstrCall(tree: Tree): Boolean = dissectApplied(tree).core match { + case Ident(nme.CONSTRUCTOR) => true + case Select(This(_), nme.CONSTRUCTOR) => true + case _ => false } /** Is tree a super constructor call? */ - def isSuperConstrCall(tree: Tree): Boolean = tree match { - case Applied(Select(Super(_, _), nme.CONSTRUCTOR), _, _) => true - case _ => false + def isSuperConstrCall(tree: Tree): Boolean = dissectApplied(tree).core match { + case Select(Super(_, _), nme.CONSTRUCTOR) => true + case _ => false } /** @@ -848,8 +848,10 @@ abstract class TreeInfo { case _ => false }) - def isMacroApplication(tree: Tree): Boolean = - !tree.isDef && tree.symbol != null && tree.symbol.isTermMacro && !tree.symbol.isErroneous + def isMacroApplication(tree: Tree): Boolean = !tree.isDef && { + val sym = tree.symbol + sym != null && sym.isTermMacro && !sym.isErroneous + } def isMacroApplicationOrBlock(tree: Tree): Boolean = tree match { case Block(_, expr) => isMacroApplicationOrBlock(expr) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 9ddaea4c62..53c528a2bb 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -1977,7 +1977,7 @@ trait Types def pendingVolatiles = _pendingVolatiles class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) { - require(args0.nonEmpty, this) + require(args0 ne Nil, this) /** No unapplied type params size it has (should have) equally as many args. */ override def isHigherKinded = false @@ -1988,12 +1988,39 @@ trait Types // too little information is known to determine its kind, and // it later turns out not to have kind *. See SI-4070. Only // logging it for now. - if (sym.typeParams.size != args.size) + val tparams = sym.typeParams + if (tparams.size != args.size) devWarning(s"$this.transform($tp), but tparams.isEmpty and args=$args") - - val GenPolyType(tparams, result) = asSeenFromOwner(tp) - assert((tparams eq Nil) || tparams == sym.typeParams, (tparams, sym.typeParams)) - result.instantiateTypeParams(sym.typeParams, args) + def asSeenFromInstantiated(tp: Type) = + asSeenFromOwner(tp).instantiateTypeParams(tparams, args) + // If we're called with a poly type, and we were to run the `asSeenFrom`, over the entire + // type, we can end up with new symbols for the type parameters (clones from TypeMap). + // The subsequent substitution of type arguments would fail. This problem showed up during + // the fix for SI-8046, however the solution taken there wasn't quite right, and led to + // SI-8170. + // + // Now, we detect the PolyType before both the ASF *and* the substitution, and just operate + // on the result type. + // + // TODO: Revisit this and explore the questions raised: + // + // AM: I like this better than the old code, but is there any way the tparams would need the ASF treatment as well? + // JZ: I think its largely irrelevant, as they are no longer referred to in the result type. + // In fact, you can get away with returning a type of kind * here and the sky doesn't fall: + // `case PolyType(`tparams`, result) => asSeenFromInstantiated(result)` + // But I thought it was better to retain the kind. + // AM: I've been experimenting with apply-type-args-then-ASF, but running into cycles. + // In general, it seems iffy the tparams can never occur in the result + // then we might as well represent the type as a no-arg typeref. + // AM: I've also been trying to track down uses of transform (pretty generic name for something that + // does not seem that widely applicable). + // It's kind of a helper for computing baseType (since it tries to propagate our type args to some + // other type, which has to be related to this type for that to make sense). + // + tp match { + case PolyType(`tparams`, result) => PolyType(tparams, asSeenFromInstantiated(result)) + case _ => asSeenFromInstantiated(tp) + } } // note: does not go through typeRef. There's no need to because @@ -2035,7 +2062,7 @@ trait Types // to a java or scala symbol, but it does matter whether it occurs in java or scala code. // TypeRefs w/o type params that occur in java signatures/code are considered raw types, and are // represented as existential types. - override def isHigherKinded = typeParams.nonEmpty + override def isHigherKinded = (typeParams ne Nil) override def typeParams = if (isDefinitionsInitialized) sym.typeParams else sym.unsafeTypeParams private def isRaw = !phase.erasedTypes && isRawIfWithoutArgs(sym) @@ -2221,7 +2248,7 @@ trait Types //OPT specialize hashCode override final def computeHashCode = { import scala.util.hashing.MurmurHash3._ - val hasArgs = args.nonEmpty + val hasArgs = args ne Nil var h = productSeed h = mix(h, pre.hashCode) h = mix(h, sym.hashCode) @@ -2412,7 +2439,7 @@ trait Types object TypeRef extends TypeRefExtractor { def apply(pre: Type, sym: Symbol, args: List[Type]): Type = unique({ - if (args.nonEmpty) { + if (args ne Nil) { if (sym.isAliasType) new AliasArgsTypeRef(pre, sym, args) else if (sym.isAbstractType) new AbstractArgsTypeRef(pre, sym, args) else new ClassArgsTypeRef(pre, sym, args) @@ -2485,7 +2512,7 @@ trait Types true } - def isImplicit = params.nonEmpty && params.head.isImplicit + def isImplicit = (params ne Nil) && params.head.isImplicit def isJava = false // can we do something like for implicits? I.e. do Java methods without parameters need to be recognized? //assert(paramTypes forall (pt => !pt.typeSymbol.isImplClass))//DEBUG @@ -2493,7 +2520,7 @@ trait Types override def paramss: List[List[Symbol]] = params :: resultType.paramss - override def paramTypes = params map (_.tpe) + override def paramTypes = mapList(params)(symTpe) // OPT use mapList rather than .map override def boundSyms = resultType.boundSyms ++ params @@ -4120,7 +4147,7 @@ trait Types && (variance.isCovariant || isSubType(t2, t1, depth)) ) - corresponds3(tps1, tps2, tparams map (_.variance))(isSubArg) + corresponds3(tps1, tps2, mapList(tparams)(_.variance))(isSubArg) } def specializesSym(tp: Type, sym: Symbol, depth: Depth): Boolean = { @@ -4304,7 +4331,7 @@ trait Types } def instantiatedBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = - tparams map (_.info.asSeenFrom(pre, owner).instantiateTypeParams(tparams, targs).bounds) + mapList(tparams)(_.info.asSeenFrom(pre, owner).instantiateTypeParams(tparams, targs).bounds) def elimAnonymousClass(t: Type) = t match { case TypeRef(pre, clazz, Nil) if clazz.isAnonymousClass => @@ -4553,7 +4580,10 @@ trait Types private[scala] val typeIsExistentiallyBound = (tp: Type) => tp.typeSymbol.isExistentiallyBound private[scala] val typeIsErroneous = (tp: Type) => tp.isErroneous private[scala] val symTypeIsError = (sym: Symbol) => sym.tpe.isError - private[scala] val typeHasAnnotations = (tp: Type) => tp.annotations.nonEmpty + private[scala] val treeTpe = (t: Tree) => t.tpe + private[scala] val symTpe = (sym: Symbol) => sym.tpe + private[scala] val symInfo = (sym: Symbol) => sym.info + private[scala] val typeHasAnnotations = (tp: Type) => tp.annotations ne Nil private[scala] val boundsContainType = (bounds: TypeBounds, tp: Type) => bounds containsType tp private[scala] val typeListIsEmpty = (ts: List[Type]) => ts.isEmpty private[scala] val typeIsSubTypeOfSerializable = (tp: Type) => tp <:< SerializableTpe diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala index 28afd18fe0..816916787e 100644 --- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala @@ -51,6 +51,8 @@ abstract class MutableSettings extends AbsSettings { def Yrecursion: IntSetting def maxClassfileName: IntSetting + + def isScala211: Boolean } object MutableSettings { diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala index 3c4e93f11d..f9b10c90be 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala @@ -173,11 +173,11 @@ trait TypeComparers { // SI-2066 This prevents overrides with incompatible variance in higher order type parameters. private def methodHigherOrderTypeParamsSameVariance(sym1: Symbol, sym2: Symbol) = { def ignoreVariance(sym: Symbol) = !(sym.isHigherOrderTypeParameter && sym.logicallyEnclosingMember.isMethod) - ignoreVariance(sym1) || ignoreVariance(sym2) || sym1.variance == sym2.variance + !settings.isScala211 || ignoreVariance(sym1) || ignoreVariance(sym2) || sym1.variance == sym2.variance } private def methodHigherOrderTypeParamsSubVariance(low: Symbol, high: Symbol) = - methodHigherOrderTypeParamsSameVariance(low, high) || low.variance.isInvariant + !settings.isScala211 || methodHigherOrderTypeParamsSameVariance(low, high) || low.variance.isInvariant def isSameType2(tp1: Type, tp2: Type): Boolean = { def retry(lhs: Type, rhs: Type) = ((lhs ne tp1) || (rhs ne tp2)) && isSameType(lhs, rhs) diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala index 09f4389b82..f427813c01 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala @@ -861,7 +861,7 @@ private[internal] trait TypeMaps { class InstantiateDependentMap(params: List[Symbol], actuals0: List[Type]) extends TypeMap with KeepOnlyTypeConstraints { private val actuals = actuals0.toIndexedSeq private val existentials = new Array[Symbol](actuals.size) - def existentialsNeeded: List[Symbol] = existentials.filter(_ ne null).toList + def existentialsNeeded: List[Symbol] = existentials.iterator.filter(_ ne null).toList private object StableArg { def unapply(param: Symbol) = Arg unapply param map actuals filter (tp => diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala index 7cc2952c96..d128521be8 100644 --- a/src/reflect/scala/reflect/internal/util/Collections.scala +++ b/src/reflect/scala/reflect/internal/util/Collections.scala @@ -47,6 +47,30 @@ trait Collections { final def mforeach[A](xss: List[List[A]])(f: A => Unit) = xss foreach (_ foreach f) final def mforeach[A](xss: Traversable[Traversable[A]])(f: A => Unit) = xss foreach (_ foreach f) + /** A version of List#map, specialized for List, and optimized to avoid allocation if `as` is empty */ + final def mapList[A, B](as: List[A])(f: A => B): List[B] = if (as eq Nil) Nil else { + val head = new ::[B](f(as.head), Nil) + var tail: ::[B] = head + var rest = as.tail + while (rest ne Nil) { + val next = new ::(f(rest.head), Nil) + tail.tl = next + tail = next + rest = rest.tail + } + head + } + + final def collectFirst[A, B](as: List[A])(pf: PartialFunction[A, B]): Option[B] = { + @tailrec + def loop(rest: List[A]): Option[B] = rest match { + case Nil => None + case a :: as if pf.isDefinedAt(a) => Some(pf(a)) + case a :: as => loop(as) + } + loop(as) + } + final def map2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => C): List[C] = { val lb = new ListBuffer[C] var ys1 = xs1 @@ -99,15 +123,19 @@ trait Collections { else f(xs1.head, xs2.head, xs3.head) :: map3(xs1.tail, xs2.tail, xs3.tail)(f) } final def flatMap2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => List[C]): List[C] = { - val lb = new ListBuffer[C] + var lb: ListBuffer[C] = null var ys1 = xs1 var ys2 = xs2 while (!ys1.isEmpty && !ys2.isEmpty) { - lb ++= f(ys1.head, ys2.head) + val cs = f(ys1.head, ys2.head) + if (cs ne Nil) { + if (lb eq null) lb = new ListBuffer[C] + lb ++= cs + } ys1 = ys1.tail ys2 = ys2.tail } - lb.toList + if (lb eq null) Nil else lb.result } final def flatCollect[A, B](elems: List[A])(pf: PartialFunction[A, Traversable[B]]): List[B] = { diff --git a/src/reflect/scala/reflect/internal/util/SourceFile.scala b/src/reflect/scala/reflect/internal/util/SourceFile.scala index 9866b043bb..8791d8eb23 100644 --- a/src/reflect/scala/reflect/internal/util/SourceFile.scala +++ b/src/reflect/scala/reflect/internal/util/SourceFile.scala @@ -40,8 +40,8 @@ abstract class SourceFile { def lineToString(index: Int): String = { val start = lineToOffset(index) var end = start - while (!isEndOfLine(end)) end += 1 - content.slice(start, end) mkString "" + while (!isEndOfLine(end) && end <= length) end += 1 + new String(content, start, end - start) } @tailrec @@ -136,14 +136,20 @@ class BatchSourceFile(val file : AbstractFile, val content0: Array[Char]) extend private def charAtIsEOL(idx: Int)(p: Char => Boolean) = { // don't identify the CR in CR LF as a line break, since LF will do. - def notCRLF0 = content(idx) != CR || idx + 1 >= length || content(idx + 1) != LF + def notCRLF0 = content(idx) != CR || !content.isDefinedAt(idx + 1) || content(idx + 1) != LF idx < length && notCRLF0 && p(content(idx)) } def isLineBreak(idx: Int) = charAtIsEOL(idx)(isLineBreakChar) - def isEndOfLine(idx: Int) = charAtIsEOL(idx) { + /** True if the index is included by an EOL sequence. */ + def isEndOfLine(idx: Int) = (content isDefinedAt idx) && PartialFunction.cond(content(idx)) { + case CR | LF => true + } + + /** True if the index is end of an EOL sequence. */ + def isAtEndOfLine(idx: Int) = charAtIsEOL(idx) { case CR | LF => true case _ => false } @@ -151,7 +157,7 @@ class BatchSourceFile(val file : AbstractFile, val content0: Array[Char]) extend def calculateLineIndices(cs: Array[Char]) = { val buf = new ArrayBuffer[Int] buf += 0 - for (i <- 0 until cs.length) if (isEndOfLine(i)) buf += i + 1 + for (i <- 0 until cs.length) if (isAtEndOfLine(i)) buf += i + 1 buf += cs.length // sentinel, so that findLine below works smoother buf.toArray } diff --git a/src/reflect/scala/reflect/macros/Attachments.scala b/src/reflect/scala/reflect/macros/Attachments.scala index 039e75fbee..5ccdc15a03 100644 --- a/src/reflect/scala/reflect/macros/Attachments.scala +++ b/src/reflect/scala/reflect/macros/Attachments.scala @@ -43,7 +43,7 @@ abstract class Attachments { self => /** Check underlying payload contains an instance of type `T`. */ def contains[T: ClassTag]: Boolean = - all exists matchesTag[T] + !isEmpty && (all exists matchesTag[T]) /** Creates a copy of this attachment with the payload slot of T added/updated with the provided value. * Replaces an existing payload of the same type, if exists. @@ -57,6 +57,8 @@ abstract class Attachments { self => if (newAll.isEmpty) pos.asInstanceOf[Attachments { type Pos = self.Pos }] else new NonemptyAttachments[Pos](this.pos, newAll) } + + def isEmpty: Boolean = true } // SI-7018: This used to be an inner class of `Attachments`, but that led to a memory leak in the @@ -64,4 +66,5 @@ abstract class Attachments { self => private final class NonemptyAttachments[P >: Null](override val pos: P, override val all: Set[Any]) extends Attachments { type Pos = P def withPos(newPos: Pos) = new NonemptyAttachments(newPos, all) + override def isEmpty: Boolean = false } diff --git a/src/reflect/scala/reflect/macros/Names.scala b/src/reflect/scala/reflect/macros/Names.scala index af60dffbfc..4f3448e1ed 100644 --- a/src/reflect/scala/reflect/macros/Names.scala +++ b/src/reflect/scala/reflect/macros/Names.scala @@ -6,33 +6,51 @@ package macros * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that - * provides functions that generate unique names. + * provides functions that generate fresh names. + * + * In the current implementation, fresh names are more or less unique in the sense that + * within the same compilation run they are guaranteed not to clash with: + * 1) Results of past and future invocations of functions of `freshName` family + * 2) User-defined or macro-generated names that don't contain dollar symbols + * 3) Macro-generated names that are created by concatenating names from the first, second and third categories + * + * Uniqueness of fresh names across compilation runs is not guaranteed, but that's something + * that we would like to improve upon in future releases. See [[https://issues.scala-lang.org/browse/SI-6879]] for more information. + * + * @define freshNameNoParams + * Creates a string that represents a more or less unique name. + * Consult [[scala.reflect.macros.Names]] for more information on uniqueness of such names. + * + * @define freshNameStringParam + * Creates a string that represents a more or less unique name having a given prefix. + * Consult [[scala.reflect.macros.Names]] for more information on uniqueness of such names. + * + * @define freshNameNameParam + * Creates a more or less unique name having a given name as a prefix and + * having the same flavor (term name or type name) as the given name. + * Consult [[scala.reflect.macros.Names]] for more information on uniqueness of such names. */ trait Names { self: blackbox.Context => - /** Creates a unique string. */ + /** $freshNameNoParams */ @deprecated("Use freshName instead", "2.11.0") def fresh(): String - /** Creates a unique string having a given prefix. */ + /** $freshNameStringParam */ @deprecated("Use freshName instead", "2.11.0") def fresh(name: String): String - /** Creates a unique name having a given name as a prefix and - * having the same flavor (term name or type name) as the given name. - */ + /** $freshNameNameParam */ @deprecated("Use freshName instead", "2.11.0") def fresh[NameType <: Name](name: NameType): NameType - /** Creates a unique string. */ + /** $freshNameNoParams */ def freshName(): String - /** Creates a unique string having a given prefix. */ + /** $freshNameStringParam */ def freshName(name: String): String - /** Creates a unique name having a given name as a prefix and - * having the same flavor (term name or type name) as the given name. - */ + /** $freshNameNameParam */ def freshName[NameType <: Name](name: NameType): NameType } diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index 54b75b8e5b..cfd66744ff 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -21,7 +21,7 @@ class JavaUniverse extends internal.SymbolTable with JavaUniverseForce with Refl def newStrictTreeCopier: TreeCopier = new StrictTreeCopier def newLazyTreeCopier: TreeCopier = new LazyTreeCopier - val currentFreshNameCreator = new reflect.internal.util.FreshNameCreator + def currentFreshNameCreator = globalFreshNameCreator // can't put this in runtime.Trees since that's mixed with Global in ReflectGlobal, which has the definition from internal.Trees object treeInfo extends { diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index b9b171c7ed..8811b5513e 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -58,6 +58,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.CompoundTypeTreeOriginalAttachment this.BackquotedIdentifierAttachment this.ForAttachment + this.SyntheticUnitAttachment this.SubpatternsAttachment this.noPrint this.typeDebug diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala index 11db83d7d5..de5ba99900 100644 --- a/src/reflect/scala/reflect/runtime/Settings.scala +++ b/src/reflect/scala/reflect/runtime/Settings.scala @@ -48,4 +48,5 @@ private[reflect] class Settings extends MutableSettings { val Yrecursion = new IntSetting(0) val maxClassfileName = new IntSetting(255) + def isScala211 = true } diff --git a/src/scaladoc/scala/tools/nsc/doc/Settings.scala b/src/scaladoc/scala/tools/nsc/doc/Settings.scala index e5dbaa3fd5..5ea1443a19 100644 --- a/src/scaladoc/scala/tools/nsc/doc/Settings.scala +++ b/src/scaladoc/scala/tools/nsc/doc/Settings.scala @@ -122,6 +122,11 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_)) "Hide the members inherited by the given comma separated, fully qualified implicit conversions. Add dot (.) to include default conversions." ) + val docAuthor = BooleanSetting ( + "-author", + "Include authors." + ) + val docDiagrams = BooleanSetting ( "-diagrams", "Create inheritance diagrams for classes, traits and packages." @@ -207,7 +212,7 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_)) // For improved help output. def scaladocSpecific = Set[Settings#Setting]( docformat, doctitle, docfooter, docversion, docUncompilable, docsourceurl, docgenerator, docRootContent, useStupidTypes, - docDiagrams, docDiagramsDebug, docDiagramsDotPath, + docAuthor, docDiagrams, docDiagramsDebug, docDiagramsDotPath, docDiagramsDotTimeout, docDiagramsDotRestart, docImplicits, docImplicitsDebug, docImplicitsShowAll, docImplicitsHide, docDiagramsMaxNormalClasses, docDiagramsMaxImplicitClasses, 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 119d4e0143..26ee005d3e 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala @@ -351,6 +351,14 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp if (mbr.comment.isEmpty) NodeSeq.Empty else <div class="comment cmt">{ commentToHtml(mbr.comment) }</div> + val authorComment = + if (! s.docAuthor || mbr.comment.isEmpty || + mbr.comment.isDefined && mbr.comment.get.authors.isEmpty) NodeSeq.Empty + else <div class="comment cmt"> + {if (mbr.comment.get.authors.size > 1) <h6>Authors:</h6> else <h6>Author:</h6>} + { mbr.comment.get.authors map bodyToHtml} + </div> + val paramComments = { val prs: List[ParameterEntity] = mbr match { case cls: Class => cls.typeParams ::: cls.valueParams.flatten @@ -681,7 +689,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp val typeHierarchy = createDiagram(_.inheritanceDiagram, "Type Hierarchy", "inheritance-diagram") val contentHierarchy = createDiagram(_.contentDiagram, "Content Hierarchy", "content-diagram") - memberComment ++ paramComments ++ attributesBlock ++ linearization ++ subclasses ++ typeHierarchy ++ contentHierarchy + memberComment ++ authorComment ++ paramComments ++ attributesBlock ++ linearization ++ subclasses ++ typeHierarchy ++ contentHierarchy } def boundsToHtml(hi: Option[TypeEntity], lo: Option[TypeEntity], hasLinks: Boolean): NodeSeq = { diff --git a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala index 8f217e087c..ef84ac42ba 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala @@ -10,6 +10,7 @@ import diagram._ import scala.collection._ import scala.util.matching.Regex +import scala.reflect.macros.internal.macroImpl import symtab.Flags import io._ @@ -80,7 +81,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def inTemplate: TemplateImpl = inTpl def toRoot: List[EntityImpl] = this :: inTpl.toRoot def qualifiedName = name - def annotations = sym.annotations.map(makeAnnotation) + def annotations = sym.annotations.filterNot(_.tpe =:= typeOf[macroImpl]).map(makeAnnotation) def inPackageObject: Boolean = sym.owner.isModuleClass && sym.owner.sourceModule.isPackageObject def isType = sym.name.isTypeName } @@ -145,6 +146,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { * any abstract terms, otherwise it would fail compilation. So we reset the DEFERRED flag. */ if (!sym.isTrait && (sym hasFlag Flags.DEFERRED) && (!isImplicitlyInherited)) fgs += Paragraph(Text("abstract")) if (!sym.isModule && (sym hasFlag Flags.FINAL)) fgs += Paragraph(Text("final")) + if (sym.isMacro) fgs += Paragraph(Text("macro")) fgs.toList } def deprecation = diff --git a/test/files/filters b/test/files/filters index 70d7dcff70..51a7507848 100644 --- a/test/files/filters +++ b/test/files/filters @@ -4,3 +4,5 @@ Java HotSpot\(TM\) .* warning: # Hotspot receiving VM options through the $_JAVA_OPTIONS # env variable outputs them on stderr Picked up _JAVA_OPTIONS: +# Filter out a message caused by this bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8021205 +objc\[\d+\]: Class JavaLaunchHelper is implemented in both .* and .*\. One of the two will be used\. Which one is undefined\. diff --git a/test/files/jvm/t6941/Analyzed_1.scala b/test/files/jvm/t6941/Analyzed_1.scala index 549abd5e64..b6951f71ee 100644 --- a/test/files/jvm/t6941/Analyzed_1.scala +++ b/test/files/jvm/t6941/Analyzed_1.scala @@ -6,6 +6,6 @@ class SameBytecode { } def b(xs: List[Int]) = xs match { - case xs: ::[Int] => xs.hd$1 + case xs: ::[Int] => xs.head } }
\ No newline at end of file diff --git a/test/files/neg/abstract-report2.check b/test/files/neg/abstract-report2.check index 6ea949353a..9be3d822f2 100644 --- a/test/files/neg/abstract-report2.check +++ b/test/files/neg/abstract-report2.check @@ -61,7 +61,7 @@ it has 13 unimplemented members. class Baz[T] extends Collection[T] ^ -abstract-report2.scala:11: error: class Dingus needs to be abstract, since: +abstract-report2.scala:15: error: class Dingus needs to be abstract, since: it has 24 unimplemented members. /** As seen from class Dingus, the missing signatures are as follows. * For convenience, these are usable as stub implementations. @@ -84,9 +84,6 @@ it has 24 unimplemented members. def toIterator: Iterator[(Set[Int], String)] = ??? def toStream: Stream[(Set[Int], String)] = ??? - // Members declared in scala.math.Ordering - def compare(x: List[Int],y: List[Int]): Int = ??? - // Members declared in scala.collection.TraversableOnce def copyToArray[B >: (Set[Int], String)](xs: Array[B],start: Int,len: Int): Unit = ??? def exists(p: ((Set[Int], String)) => Boolean): Boolean = ??? @@ -98,6 +95,9 @@ it has 24 unimplemented members. def seq: scala.collection.TraversableOnce[(Set[Int], String)] = ??? def toTraversable: Traversable[(Set[Int], String)] = ??? + // Members declared in Xyz + def foo(x: List[Int]): Boolean = ??? + class Dingus extends Bippy[String, Set[Int], List[Int]] ^ four errors found diff --git a/test/files/neg/abstract-report2.scala b/test/files/neg/abstract-report2.scala index b6327b0766..8825340d4a 100644 --- a/test/files/neg/abstract-report2.scala +++ b/test/files/neg/abstract-report2.scala @@ -6,6 +6,10 @@ class Bar extends Collection[List[_ <: String]] class Baz[T] extends Collection[T] -trait Bippy[T1, T2, T3] extends Collection[T1] with TraversableOnce[(T2, String)] with Ordering[T3] +trait Xyz[T] { + def foo(x: T): Boolean +} + +trait Bippy[T1, T2, T3] extends Collection[T1] with TraversableOnce[(T2, String)] with Xyz[T3] class Dingus extends Bippy[String, Set[Int], List[Int]]
\ No newline at end of file diff --git a/test/files/neg/accesses.check b/test/files/neg/accesses.check index 5a5e03233e..db58af12ce 100644 --- a/test/files/neg/accesses.check +++ b/test/files/neg/accesses.check @@ -1,3 +1,7 @@ +accesses.scala:23: error: overriding method f2 in class A of type ()Unit; + method f2 has weaker access privileges; it should not be private + private def f2(): Unit = () + ^ accesses.scala:24: error: overriding method f3 in class A of type ()Unit; method f3 has weaker access privileges; it should be at least protected private[p2] def f3(): Unit = () @@ -10,4 +14,4 @@ accesses.scala:26: error: overriding method f5 in class A of type ()Unit; method f5 has weaker access privileges; it should be at least protected[p1] protected[p2] def f5(): Unit ^ -three errors found +four errors found diff --git a/test/files/neg/accesses2.check b/test/files/neg/accesses2.check index 554a7b4c81..66cf9a116e 100644 --- a/test/files/neg/accesses2.check +++ b/test/files/neg/accesses2.check @@ -1,4 +1,12 @@ +accesses2.scala:6: error: overriding method f2 in class A of type ()Int; + method f2 has weaker access privileges; it should not be private + private def f2(): Int = 1 + ^ accesses2.scala:5: error: class B1 needs to be abstract, since method f2 in class A of type ()Int is not defined class B1 extends A { ^ -one error found +accesses2.scala:9: error: overriding method f2 in class A of type ()Int; + method f2 has weaker access privileges; it should not be private + private def f2(): Int = 1 + ^ +three errors found diff --git a/test/files/neg/missing-param-type-tuple.check b/test/files/neg/missing-param-type-tuple.check index bc46ba1023..3a4258ff8c 100644 --- a/test/files/neg/missing-param-type-tuple.check +++ b/test/files/neg/missing-param-type-tuple.check @@ -1,6 +1,6 @@ missing-param-type-tuple.scala:3: error: missing parameter type Note: The expected type requires a one-argument function accepting a 2-Tuple. - Consider a pattern matching anoynmous function, `{ case (a, b) => ... }` + Consider a pattern matching anonymous function, `{ case (a, b) => ... }` val x: ((Int, Int)) => Int = (a, b) => 0 ^ missing-param-type-tuple.scala:3: error: missing parameter type @@ -8,7 +8,7 @@ missing-param-type-tuple.scala:3: error: missing parameter type ^ missing-param-type-tuple.scala:5: error: missing parameter type Note: The expected type requires a one-argument function accepting a 3-Tuple. - Consider a pattern matching anoynmous function, `{ case (param1, ..., param3) => ... }` + Consider a pattern matching anonymous function, `{ case (param1, ..., param3) => ... }` val y: ((Int, Int, Int)) => Int = (a, b, !!) => 0 ^ missing-param-type-tuple.scala:5: error: missing parameter type @@ -19,7 +19,7 @@ missing-param-type-tuple.scala:5: error: missing parameter type ^ missing-param-type-tuple.scala:7: error: missing parameter type Note: The expected type requires a one-argument function accepting a 3-Tuple. - Consider a pattern matching anoynmous function, `{ case (param1, ..., param3) => ... }` + Consider a pattern matching anonymous function, `{ case (param1, ..., param3) => ... }` val z: ((Int, Int, Int)) => Int = (a, NotAVariablePatternName, c) => 0 ^ missing-param-type-tuple.scala:7: error: missing parameter type diff --git a/test/files/neg/no-implicit-to-anyref-any-val.check b/test/files/neg/no-implicit-to-anyref-any-val.check new file mode 100644 index 0000000000..5953e1bd6d --- /dev/null +++ b/test/files/neg/no-implicit-to-anyref-any-val.check @@ -0,0 +1,34 @@ +no-implicit-to-anyref-any-val.scala:11: error: the result type of an implicit conversion must be more specific than AnyRef + 1: AnyRef + ^ +no-implicit-to-anyref-any-val.scala:17: error: type mismatch; + found : Any + required: AnyRef + (null: Any): AnyRef + ^ +no-implicit-to-anyref-any-val.scala:21: error: type mismatch; + found : AnyVal + required: AnyRef + (0: AnyVal): AnyRef + ^ +no-implicit-to-anyref-any-val.scala:27: error: type mismatch; + found : Test.AV + required: AnyRef +Note that AV extends Any, not AnyRef. +Such types can participate in value classes, but instances +cannot appear in singleton types or in reference comparisons. + new AV(0): AnyRef + ^ +no-implicit-to-anyref-any-val.scala:30: error: the result type of an implicit conversion must be more specific than AnyVal + "": AnyVal + ^ +no-implicit-to-anyref-any-val.scala:32: error: type mismatch; + found : Object + required: AnyVal +Note that implicit conversions are not applicable because they are ambiguous: + both method ArrowAssoc in object Predef of type [A](self: A)ArrowAssoc[A] + and method Ensuring in object Predef of type [A](self: A)Ensuring[A] + are possible conversion functions from Object to AnyVal + new Object() : AnyVal + ^ +6 errors found diff --git a/test/files/neg/no-implicit-to-anyref.scala b/test/files/neg/no-implicit-to-anyref-any-val.scala index 3e3d373e38..f5daf541af 100644 --- a/test/files/neg/no-implicit-to-anyref.scala +++ b/test/files/neg/no-implicit-to-anyref-any-val.scala @@ -26,4 +26,8 @@ object Test { locally { new AV(0): AnyRef } + + "": AnyVal + + new Object() : AnyVal } diff --git a/test/files/neg/no-implicit-to-anyref.check b/test/files/neg/no-implicit-to-anyref.check deleted file mode 100644 index fe417ad8b0..0000000000 --- a/test/files/neg/no-implicit-to-anyref.check +++ /dev/null @@ -1,22 +0,0 @@ -no-implicit-to-anyref.scala:11: error: the result type of an implicit conversion must be more specific than AnyRef - 1: AnyRef - ^ -no-implicit-to-anyref.scala:17: error: type mismatch; - found : Any - required: AnyRef - (null: Any): AnyRef - ^ -no-implicit-to-anyref.scala:21: error: type mismatch; - found : AnyVal - required: AnyRef - (0: AnyVal): AnyRef - ^ -no-implicit-to-anyref.scala:27: error: type mismatch; - found : Test.AV - required: AnyRef -Note that AV extends Any, not AnyRef. -Such types can participate in value classes, but instances -cannot appear in singleton types or in reference comparisons. - new AV(0): AnyRef - ^ -four errors found diff --git a/test/files/neg/quasiquotes-syntax-error-position.check b/test/files/neg/quasiquotes-syntax-error-position.check index 25e5b8d75a..14fef16e01 100644 --- a/test/files/neg/quasiquotes-syntax-error-position.check +++ b/test/files/neg/quasiquotes-syntax-error-position.check @@ -29,4 +29,7 @@ quasiquotes-syntax-error-position.scala:13: error: end of quote expected but 'ca quasiquotes-syntax-error-position.scala:14: error: ')' expected but end of quote found. pq"$a(bar" ^ -10 errors found +quasiquotes-syntax-error-position.scala:15: error: ':' expected but ')' found. + q"def foo(x)" + ^ +11 errors found diff --git a/test/files/neg/quasiquotes-syntax-error-position.scala b/test/files/neg/quasiquotes-syntax-error-position.scala index b97af52cfc..7b1d66ba00 100644 --- a/test/files/neg/quasiquotes-syntax-error-position.scala +++ b/test/files/neg/quasiquotes-syntax-error-position.scala @@ -12,4 +12,5 @@ object test extends App { tq"$t => $t $t]" cq"pattern => body ; case pattern2 =>" pq"$a(bar" -}
\ No newline at end of file + q"def foo(x)" +} diff --git a/test/files/neg/t6844.check b/test/files/neg/t6844.check new file mode 100644 index 0000000000..1fc2485520 --- /dev/null +++ b/test/files/neg/t6844.check @@ -0,0 +1,6 @@ +t6844.scala:4: error: type mismatch; + found : reflect.runtime.universe.TermName + required: reflect.runtime.universe.Tree + q"def foo($x)" + ^ +one error found diff --git a/test/files/neg/t6844.scala b/test/files/neg/t6844.scala new file mode 100644 index 0000000000..809d9d0f98 --- /dev/null +++ b/test/files/neg/t6844.scala @@ -0,0 +1,5 @@ +import scala.reflect.runtime.universe._ +object Test extends App { + val x = TermName("x") + q"def foo($x)" +} diff --git a/test/files/neg/t8143a.check b/test/files/neg/t8143a.check new file mode 100644 index 0000000000..4e11000a2a --- /dev/null +++ b/test/files/neg/t8143a.check @@ -0,0 +1,5 @@ +t8143a.scala:2: error: overriding method f in class Foo of type => Int; + method f has weaker access privileges; it should not be private +class Bar extends Foo { private def f = 10 } + ^ +one error found diff --git a/test/files/neg/t8143a.scala b/test/files/neg/t8143a.scala new file mode 100644 index 0000000000..4ec539e671 --- /dev/null +++ b/test/files/neg/t8143a.scala @@ -0,0 +1,15 @@ +class Foo { def f = 5 } +class Bar extends Foo { private def f = 10 } + + +class Foo1 { private def f = 5 } +class Bar1 extends Foo1 { def f = 10 } // okay + +class Foo2 { private def f = 5 } +class Bar2 extends Foo2 { private def f = 10 } // okay + +class Foo3 { private[this] def f = 5 } +class Bar3 extends Foo3 { private def f = 10 } // okay + +class Foo4 { private def f = 5 } +class Bar4 extends Foo4 { private[this] def f = 10 } // okay
\ No newline at end of file diff --git a/test/files/neg/t8182.check b/test/files/neg/t8182.check new file mode 100644 index 0000000000..a156d70883 --- /dev/null +++ b/test/files/neg/t8182.check @@ -0,0 +1,22 @@ +t8182.scala:4: error: illegal start of simple pattern +} +^ +t8182.scala:7: error: illegal start of simple pattern +} +^ +t8182.scala:6: error: type application is not allowed in pattern + val a b[B] // error then continue as for X + ^ +t8182.scala:10: error: illegal start of simple pattern + case a b[B] => // bumpy recovery + ^ +t8182.scala:10: error: type application is not allowed in pattern + case a b[B] => // bumpy recovery + ^ +t8182.scala:11: error: '=>' expected but '}' found. + } + ^ +t8182.scala:16: error: type application is not allowed in pattern + case a B[T] b => + ^ +7 errors found diff --git a/test/files/neg/t8182.scala b/test/files/neg/t8182.scala new file mode 100644 index 0000000000..1b3bc9821f --- /dev/null +++ b/test/files/neg/t8182.scala @@ -0,0 +1,18 @@ + +trait X { + val a b // something missing +} +trait Y { + val a b[B] // error then continue as for X +} +trait Z { + (null: Any) match { + case a b[B] => // bumpy recovery + } +} +object B { def unapply[W](a: Any) = Some((1,2)) } +trait Z { + (null: Any) match { + case a B[T] b => + } +} diff --git a/test/files/neg/t8228.check b/test/files/neg/t8228.check new file mode 100644 index 0000000000..02eff4b1b7 --- /dev/null +++ b/test/files/neg/t8228.check @@ -0,0 +1,4 @@ +t8228.scala:4: error: recursive value foo needs type + val foo = foo(null) + ^ +one error found diff --git a/test/files/neg/t8228.scala b/test/files/neg/t8228.scala new file mode 100644 index 0000000000..19d71aeab4 --- /dev/null +++ b/test/files/neg/t8228.scala @@ -0,0 +1,7 @@ +object X { + def bar = { + def foo(x: Any) = "" + val foo = foo(null) + foo(null) // cycle in isApplicableBasedOnArity + } +} diff --git a/test/files/pos/implicit-anyval-2.10.flags b/test/files/pos/implicit-anyval-2.10.flags new file mode 100644 index 0000000000..94c8056747 --- /dev/null +++ b/test/files/pos/implicit-anyval-2.10.flags @@ -0,0 +1 @@ +-Xsource:2.10 diff --git a/test/files/pos/implicit-anyval-2.10.scala b/test/files/pos/implicit-anyval-2.10.scala new file mode 100644 index 0000000000..3082af73b8 --- /dev/null +++ b/test/files/pos/implicit-anyval-2.10.scala @@ -0,0 +1,3 @@ +object Test { + "": AnyVal // newly prohibited in 2.11, allowed under -Xsourse:2.10 +}
\ No newline at end of file diff --git a/test/files/pos/t2066-2.10-compat.flags b/test/files/pos/t2066-2.10-compat.flags new file mode 100644 index 0000000000..94c8056747 --- /dev/null +++ b/test/files/pos/t2066-2.10-compat.flags @@ -0,0 +1 @@ +-Xsource:2.10 diff --git a/test/files/pos/t2066-2.10-compat.scala b/test/files/pos/t2066-2.10-compat.scala new file mode 100644 index 0000000000..fb8103e4ad --- /dev/null +++ b/test/files/pos/t2066-2.10-compat.scala @@ -0,0 +1,71 @@ +import language._ +trait A1 { + def f[T[_]] = () +} + +trait B1 extends A1 { + override def f[T[+_]] = () +} + +trait C1 extends A1 { + override def f[T[-_]] = () +} + + +trait A2 { + def f[T[+_]] = () +} + +trait B2 extends A2 { + override def f[T[_]] = () // okay +} + +trait C2 extends A2 { + override def f[T[-_]] = () +} + + +trait A3 { + def f[T[-_]] = () +} + +trait B3 extends A3 { + override def f[T[_]] = () // okay +} + +trait C3 extends A3 { + override def f[T[-_]] = () +} + + +trait A4 { + def f[T[X[+_]]] = () +} + +trait B4 extends A4 { + override def f[T[X[_]]] = () +} + +trait A5 { + def f[T[X[-_]]] = () +} + +trait B5 extends A5 { + override def f[T[X[_]]] = () +} + + + +trait A6 { + def f[T[X[_]]] = () +} + +trait B6 extends A6 { + override def f[T[X[+_]]] = () // okay +} +trait C6 extends A6 { + override def f[T[X[_]]] = () // okay +} +trait D6 extends A6 { + override def f[T[X[-_]]] = () +} diff --git a/test/files/pos/t7322.scala b/test/files/pos/t7322.scala new file mode 100644 index 0000000000..006bf89e9f --- /dev/null +++ b/test/files/pos/t7322.scala @@ -0,0 +1,11 @@ + +package object t7322 { + implicit class X(sc: StringContext) { + def x_?(args: Any*) = "hi there" + } +} +package t7322 { + trait Y { + x_?"junk" // assume that if it compiles, it works + } +} diff --git a/test/files/pos/t7919.scala b/test/files/pos/t7919.scala new file mode 100644 index 0000000000..64f261ec16 --- /dev/null +++ b/test/files/pos/t7919.scala @@ -0,0 +1,6 @@ + +object X { + val x = s"" + val y = true +} + diff --git a/test/files/pos/t8170.scala b/test/files/pos/t8170.scala new file mode 100644 index 0000000000..b65f4b8572 --- /dev/null +++ b/test/files/pos/t8170.scala @@ -0,0 +1,27 @@ +object O { + trait X + trait B extends A { + override type T[F1 <: X] = F1 + } + trait A { + type T[F <: X] + } +} + +object Test { + import O._ + val a: B = ??? + val b: a.T[X] = ??? + b.ensuring(x => true) // trigger an implicit search +} + + +/* +this = {AliasArgsTypeRef@3004}"Test#7680.a#14899.T#14823[O#7702.X#7793]" + sym = type T#14823 + info = namer: [F#14824 <: O#7703.X#7793]F#14824 +result = {AbstractNoArgsTypeRef@3237}"F#24451" +tp = {PolyType@3235}"[F#14824 <: O#7703.X#7793]F#14824" +tparams = + (0) = {AbstractTypeSymbol@3247}"type F#24451" +*/
\ No newline at end of file diff --git a/test/files/pos/t8170b.scala b/test/files/pos/t8170b.scala new file mode 100644 index 0000000000..53036f6c8a --- /dev/null +++ b/test/files/pos/t8170b.scala @@ -0,0 +1,25 @@ +import language._ + +object ScalaZeee { + trait HFold[M[_], U] { + type Apply[E, A <: U] <: U + } + trait GenericCons[M[_], H, +T <: GenericList[M]] extends GenericList[M] { + val tail: T + override type Folded[N[X] >: M[X], U, F <: HFold[N, U]] = F#Apply[H, tail.Folded[N, U, F]] + } + val KNil: GenericList[Nothing] = ??? + sealed trait GenericList[+M[_]] { + type Folded[N[X] >: M[X], U, F <: HFold[N, U]] <: U + } +} + +object TypelevelUsage { + import ScalaZeee._ + type T = GenericCons[Some, String, KNil.type] + val klist1: T = ??? + type T2 = klist1.Folded[Option, Int, HFold[Option, Int]] + val count2: T2 = ??? + + count2.ensuring(x => true).toChar // trigger an implicit search +} diff --git a/test/files/run/global-showdef.scala b/test/files/run/global-showdef.scala index c3ace590ed..1d4891fd1f 100644 --- a/test/files/run/global-showdef.scala +++ b/test/files/run/global-showdef.scala @@ -54,7 +54,7 @@ object Bippy { val run = new compiler.Run() run.compileSources(List(src)) } - output.linesIterator.toList + output.lines.toList } def showClass(name: String) = lines("-Yshow:typer", "-Xshow-class", name) def showObject(name: String) = lines("-Yshow:typer", "-Xshow-object", name) diff --git a/test/files/run/macro-abort-fresh.check b/test/files/run/macro-abort-fresh.check index 9fddee57d4..5064b96eef 100644 --- a/test/files/run/macro-abort-fresh.check +++ b/test/files/run/macro-abort-fresh.check @@ -1,6 +1,6 @@ -fresh$1 -qwe1 -qwe2 +fresh$macro$1 +qwe$macro$2 +qwe$macro$3 reflective compilation has failed: blargh diff --git a/test/files/run/private-override.scala b/test/files/run/private-override.scala deleted file mode 100644 index 0a3f57f97c..0000000000 --- a/test/files/run/private-override.scala +++ /dev/null @@ -1,17 +0,0 @@ -package test.p1.p2 { - abstract class A { - private[p2] def f2(): Int = 1 - } - abstract class Other extends A { - // It's a private method - not a private[p2] method. Not a failed - // "weaker access privileges" override, a different namespace. - private def f2(): Int = super.f2() + 2 - def go() = f2() - } -} - -object Test extends test.p1.p2.Other { - def main(args: Array[String]): Unit = { - println(go()) - } -} diff --git a/test/files/run/t6261.scala b/test/files/run/t6261.scala index b4463256c9..bf6d640de3 100644 --- a/test/files/run/t6261.scala +++ b/test/files/run/t6261.scala @@ -2,12 +2,6 @@ import scala.collection.immutable._ object Test extends App { - def test0() { - val m=ListMap(1->2,3->4) - if(m.tail ne m.tail) - println("ListMap.tail uses a builder, so it is not O(1)") - } - def test1() { // test that a HashTrieMap with one leaf element is not created! val x = HashMap.empty + (1->1) + (2->2) @@ -92,7 +86,6 @@ object Test extends App { // StructureTests.printStructure(z) require(z.size == 2 && z.contains(a._1) && z.contains(c._1)) } - test0() test1() test2() test3() diff --git a/test/files/run/t7445.scala b/test/files/run/t7445.scala new file mode 100644 index 0000000000..e4ffeb8e1a --- /dev/null +++ b/test/files/run/t7445.scala @@ -0,0 +1,6 @@ +import scala.collection.immutable.ListMap + +object Test extends App { + val a = ListMap(1 -> 1, 2 -> 2, 3 -> 3, 4 -> 4, 5 -> 5); + require(a.tail == ListMap(2 -> 2, 3 -> 3, 4 -> 4, 5 -> 5)); +} diff --git a/test/files/run/t7700.check b/test/files/run/t7700.check new file mode 100644 index 0000000000..ca8e686984 --- /dev/null +++ b/test/files/run/t7700.check @@ -0,0 +1,2 @@ +public abstract java.lang.Object C.bar(java.lang.Object) +public abstract java.lang.Object C.foo(java.lang.Object) diff --git a/test/files/run/t7700.scala b/test/files/run/t7700.scala new file mode 100644 index 0000000000..76d16b808c --- /dev/null +++ b/test/files/run/t7700.scala @@ -0,0 +1,17 @@ +import scala.annotation._ + +trait C[@specialized U] { + @unspecialized + def foo(u: U): U + @unspecialized + def bar[A](u: U) = u +} + +object Test extends App { + val declared = classOf[C[_]].getDeclaredMethods.sortBy(_.getName) + println(declared.mkString("\n")) + object CInt extends C[Int] { def foo(i: Int) = i } + object CAny extends C[Any] { def foo(a: Any) = a } + assert(CInt.foo(1) == 1) + assert(CAny.foo("") == "") +} diff --git a/test/files/run/t8199.scala b/test/files/run/t8199.scala new file mode 100644 index 0000000000..50994159ed --- /dev/null +++ b/test/files/run/t8199.scala @@ -0,0 +1,105 @@ +class reallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongname { +object obj0 +object obj01 +object obj012 +object obj0123 +object obj01234 +object obj012345 +object obj0123456 +object obj01234567 +object obj012345678 +object obj0123456789 +object obj01234567890 +class cls0 +class cls01 +class cls012 +class cls0123 +class cls01234 +class cls012345 +class cls0123456 +class cls01234567 +class cls012345678 +class cls0123456789 +class cls01234567890 +trait trt0 { def x = Test.checkCallerImplClassName() } +trait trt01 { def x = Test.checkCallerImplClassName() } +trait trt012 { def x = Test.checkCallerImplClassName() } +trait trt0123 { def x = Test.checkCallerImplClassName() } +trait trt01234 { def x = Test.checkCallerImplClassName() } +trait trt012345 { def x = Test.checkCallerImplClassName() } +trait trt0123456 { def x = Test.checkCallerImplClassName() } +trait trt01234567 { def x = Test.checkCallerImplClassName() } +trait trt012345678 { def x = Test.checkCallerImplClassName() } +trait trt0123456789 { def x = Test.checkCallerImplClassName() } +trait trt01234567890 { def x = Test.checkCallerImplClassName() } +} + +object Test extends App { + def check(c: Class[_]) { + checkClassName(c.getName) + } + def checkClassName(name: String) { + val defaultMaxClassFileLength = 255 + assert((name + ".class").length <= defaultMaxClassFileLength, name) + } + def checkCallerImplClassName() { + val name = Thread.currentThread.getStackTrace.apply(2).getClassName + assert(name.contains("$class")) + Test.checkClassName(name) + } + + val c = new reallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongname + import c._ + + check(obj0.getClass) + check(obj01.getClass) + check(obj012.getClass) + check(obj0123.getClass) + check(obj01234.getClass) + check(obj012345.getClass) + check(obj0123456.getClass) + check(obj01234567.getClass) + check(obj012345678.getClass) + check(obj0123456789.getClass) + check(obj01234567890.getClass) + + check(classOf[cls0]) + check(classOf[cls01]) + check(classOf[cls012]) + check(classOf[cls0123]) + check(classOf[cls01234]) + check(classOf[cls012345]) + check(classOf[cls0123456]) + check(classOf[cls01234567]) + check(classOf[cls012345678]) + check(classOf[cls0123456789]) + check(classOf[cls01234567890]) + + // interface facets + check(classOf[trt0]) + check(classOf[trt01]) + check(classOf[trt012]) + check(classOf[trt0123]) + check(classOf[trt01234]) + check(classOf[trt012345]) + check(classOf[trt0123456]) + check(classOf[trt01234567]) + check(classOf[trt012345678]) + check(classOf[trt0123456789]) + check(classOf[trt01234567890]) + + // impl classes are harder to find the names of to test! + (new trt0 {}).x + (new trt01 {}).x + (new trt012 {}).x + (new trt0123 {}).x + (new trt01234 {}).x + (new trt012345 {}).x + (new trt0123456 {}).x + (new trt01234567 {}).x + (new trt012345678 {}).x + (new trt0123456789 {}).x + (new trt01234567890 {}).x +} + +// filename too long: reallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongname$obj012345$.class diff --git a/test/files/run/t8233-bcode.flags b/test/files/run/t8233-bcode.flags new file mode 100644 index 0000000000..c30091d3de --- /dev/null +++ b/test/files/run/t8233-bcode.flags @@ -0,0 +1 @@ +-Ybackend:GenBCode diff --git a/test/files/run/t8233-bcode.scala b/test/files/run/t8233-bcode.scala new file mode 100644 index 0000000000..fae1c2b702 --- /dev/null +++ b/test/files/run/t8233-bcode.scala @@ -0,0 +1,18 @@ +object Test { + def bar(s: String) = s; + val o: Option[Null] = None + def nullReference { + val a: Null = o.get + bar(a) // Was: VerifyError under GenICode + } + + def literal { + val a: Null = null + bar(a) + } + + def main(args: Array[String]) = { + try { nullReference } catch { case _: NoSuchElementException => } + literal + } +} diff --git a/test/files/run/t8233.scala b/test/files/run/t8233.scala new file mode 100644 index 0000000000..fae1c2b702 --- /dev/null +++ b/test/files/run/t8233.scala @@ -0,0 +1,18 @@ +object Test { + def bar(s: String) = s; + val o: Option[Null] = None + def nullReference { + val a: Null = o.get + bar(a) // Was: VerifyError under GenICode + } + + def literal { + val a: Null = null + bar(a) + } + + def main(args: Array[String]) = { + try { nullReference } catch { case _: NoSuchElementException => } + literal + } +} diff --git a/test/files/run/var-arity-class-symbol.scala b/test/files/run/var-arity-class-symbol.scala new file mode 100644 index 0000000000..29fe960eb3 --- /dev/null +++ b/test/files/run/var-arity-class-symbol.scala @@ -0,0 +1,19 @@ +import scala.reflect.runtime.universe._, definitions._ +object Test extends App { + // Tuples + assert(TupleClass.seq.size == 22) + assert(TupleClass(0) == NoSymbol) + assert(TupleClass(23) == NoSymbol) + assert((1 to 22).forall { i => TupleClass(i).name.toString == s"Tuple$i" }) + // Functions + assert(FunctionClass.seq.size == 23) + assert(FunctionClass(-1) == NoSymbol) + assert(FunctionClass(23) == NoSymbol) + assert((0 to 22).forall { i => FunctionClass(i).name.toString == s"Function$i" }) + // Products + assert(ProductClass.seq.size == 23) + assert(ProductClass(-1) == NoSymbol) + assert(ProductClass(0) == UnitClass) + assert(ProductClass(23) == NoSymbol) + assert((1 to 22).forall { i => ProductClass(i).name.toString == s"Product$i" }) +} diff --git a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala index 2af656c7c9..3166eb7a99 100644 --- a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala @@ -7,6 +7,7 @@ object DefinitionConstructionProps with TraitConstruction with TypeDefConstruction with ValDefConstruction + with DefConstruction with PackageConstruction { property("SI-6842") = test { val x: Tree = q"val x: Int" @@ -349,4 +350,16 @@ trait PackageConstruction { self: QuasiquoteProperties => assertEqAst(q"package object foo extends { ..$edefs } with Any", "package object foo extends { val x = 1; type I = Int } with Any") } -}
\ No newline at end of file +} + +trait DefConstruction { self: QuasiquoteProperties => + property("construct implicit args (1)") = test { + val x = q"val x: Int" + assertEqAst(q"def foo(implicit $x) = x", "def foo(implicit x: Int) = x") + } + + property("construct implicit args (2)") = test { + val xs = q"val x1: Int" :: q"val x2: Long" :: Nil + assertEqAst(q"def foo(implicit ..$xs) = x1 + x2", "def foo(implicit x1: Int, x2: Long) = x1 + x2") + } +} diff --git a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala index 94465930ed..209fe9bbeb 100644 --- a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala @@ -8,6 +8,7 @@ object DefinitionDeconstructionProps with ObjectDeconstruction with ModsDeconstruction with ValVarDeconstruction + with DefDeconstruction with PackageDeconstruction trait TraitDeconstruction { self: QuasiquoteProperties => @@ -179,4 +180,32 @@ trait PackageDeconstruction { self: QuasiquoteProperties => matches("package object foo extends { val early = 1 } with daddy") assertThrows[MatchError] { matches("object foo") } } -}
\ No newline at end of file +} + +trait DefDeconstruction { self: QuasiquoteProperties => + property("exhaustive def matcher") = test { + def matches(line: String) = { + val t = parse(line) + val q"$mods0 def $name0[..$targs0](...$argss0): $restpe0 = $body0" = t + val q"$mods1 def $name1[..$targs1](...$argss1)(implicit ..$impl1): $restpe1 = $body1" = t + } + matches("def foo = foo") + matches("implicit def foo: Int = 2") + matches("def foo[T](x: T): T = x") + matches("def foo[A: B] = implicitly[B[A]]") + matches("private def foo = 0") + matches("def foo[A <% B] = null") + matches("def foo(one: One)(two: Two) = (one, two)") + matches("def foo[T](args: T*) = args.toList") + } + + property("extract implicit arg list (1)") = test { + val q"def foo(...$argss)(implicit ..$impl)" = q"def foo(x: Int)(implicit y: Int)" + assert(impl ≈ List(q"${Modifiers(IMPLICIT | PARAM)} val y: Int")) + } + + property("extract implicit arg list (2)") = test { + val q"def foo(...$argss)(implicit ..$impl)" = q"def foo(x: Int)" + assert(impl.isEmpty) + } +} diff --git a/test/files/scalacheck/quasiquotes/ErrorProps.scala b/test/files/scalacheck/quasiquotes/ErrorProps.scala index 92d299bede..3a66574c7d 100644 --- a/test/files/scalacheck/quasiquotes/ErrorProps.scala +++ b/test/files/scalacheck/quasiquotes/ErrorProps.scala @@ -52,13 +52,6 @@ object ErrorProps extends QuasiquoteProperties("errors") { StringContext("\"", "\"").q(x) """) - property("expected different cardinality") = fails( - "Can't splice List[reflect.runtime.universe.Tree] with ..., consider using ..", - """ - val args: List[Tree] = Nil - q"f(...$args)" - """) - property("non-liftable type ..") = fails( "Can't splice List[StringBuilder] with .., consider omitting the dots or providing an implicit instance of Liftable[StringBuilder]", """ @@ -90,13 +83,6 @@ object ErrorProps extends QuasiquoteProperties("errors") { q"$xs" """) - property("use zero card") = fails( - "Can't splice reflect.runtime.universe.Tree with .., consider omitting the dots", - """ - val t = EmptyTree - q"f(..$t)" - """) - property("not liftable or natively supported") = fails( "Can't splice StringBuilder, consider providing an implicit instance of Liftable[StringBuilder]", """ @@ -188,4 +174,4 @@ object ErrorProps extends QuasiquoteProperties("errors") { // // Make sure a nice error is reported in this case // { import Flag._; val mods = NoMods; q"lazy $mods val x: Int" } -}
\ No newline at end of file +} diff --git a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala index 38fbfa9f7f..54187d68c2 100644 --- a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala @@ -116,7 +116,7 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { def blockInvariant(quote: Tree, trees: List[Tree]) = quote ≈ (trees match { - case Nil => q"()" + case Nil => q"" case _ :+ last if !last.isTerm => Block(trees, q"()") case head :: Nil => head case init :+ last => Block(init, last) @@ -229,4 +229,66 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { val q"($a, $b) => $_" = q"_ + _" assert(a.name != b.name) } + + property("SI-7275 a") = test { + val t = q"stat1; stat2" + assertEqAst(q"..$t", "{stat1; stat2}") + } + + property("SI-7275 b") = test { + def f(t: Tree) = q"..$t" + assertEqAst(f(q"stat1; stat2"), "{stat1; stat2}") + } + + property("SI-7275 c1") = test { + object O + implicit val liftO = Liftable[O.type] { _ => q"foo; bar" } + assertEqAst(q"f(..$O)", "f(foo, bar)") + } + + property("SI-7275 c2") = test { + object O + implicit val liftO = Liftable[O.type] { _ => q"{ foo; bar }; { baz; bax }" } + assertEqAst(q"f(...$O)", "f(foo, bar)(baz, bax)") + } + + property("SI-7275 d") = test { + val l = q"a; b" :: q"c; d" :: Nil + assertEqAst(q"f(...$l)", "f(a, b)(c, d)") + val l2: Iterable[Tree] = l + assertEqAst(q"f(...$l2)", "f(a, b)(c, d)") + } + + property("SI-7275 e") = test { + val t = q"{ a; b }; { c; d }" + assertEqAst(q"f(...$t)", "f(a, b)(c, d)") + } + + property("SI-7275 e2") = test { + val t = q"{ a; b }; c; d" + assertEqAst(q"f(...$t)", "f(a, b)(c)(d)") + } + + property("remove synthetic unit") = test { + val q"{ ..$stats1 }" = q"{ def x = 2 }" + assert(stats1 ≈ List(q"def x = 2")) + val q"{ ..$stats2 }" = q"{ class X }" + assert(stats2 ≈ List(q"class X")) + val q"{ ..$stats3 }" = q"{ type X = Int }" + assert(stats3 ≈ List(q"type X = Int")) + val q"{ ..$stats4 }" = q"{ val x = 2 }" + assert(stats4 ≈ List(q"val x = 2")) + } + + property("don't remove user-defined unit") = test { + val q"{ ..$stats }" = q"{ def x = 2; () }" + assert(stats ≈ List(q"def x = 2", q"()")) + } + + property("empty-tree as block") = test { + val q"{ ..$stats1 }" = q" " + assert(stats1.isEmpty) + val stats2 = List.empty[Tree] + assert(q"{ ..$stats2 }" ≈ q"") + } } diff --git a/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala b/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala index be7a96d91e..0984032084 100644 --- a/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala @@ -28,4 +28,10 @@ object TypeConstructionProps extends QuasiquoteProperties("type construction") val restpe = tq"C" assert(tq"..$argtpes => $restpe" ≈ tq"(A, B) => C") } -}
\ No newline at end of file + + property("empty tq") = test { + val tt: TypeTree = tq" " + assert(tt.tpe == null) + assert(tt.original == null) + } +} diff --git a/test/junit/scala/collection/SetMapConsistencyTest.scala b/test/junit/scala/collection/SetMapConsistencyTest.scala index c62b074483..7bb8ca958b 100644 --- a/test/junit/scala/collection/SetMapConsistencyTest.scala +++ b/test/junit/scala/collection/SetMapConsistencyTest.scala @@ -476,4 +476,16 @@ class SetMapConsistencyTest { } assert(test) } + + @Test + def si8213() { + val am = new scala.collection.mutable.AnyRefMap[String, Int] + for (i <- 0 until 1024) am += i.toString -> i + am.getOrElseUpdate("1024", { am.clear; -1 }) + assert(am == scala.collection.mutable.AnyRefMap("1024" -> -1)) + val lm = new scala.collection.mutable.LongMap[Int] + for (i <- 0 until 1024) lm += i.toLong -> i + lm.getOrElseUpdate(1024, { lm.clear; -1 }) + assert(lm == scala.collection.mutable.LongMap(1024L -> -1)) + } } diff --git a/test/junit/scala/reflect/internal/util/SourceFileTest.scala b/test/junit/scala/reflect/internal/util/SourceFileTest.scala new file mode 100644 index 0000000000..903e705ba2 --- /dev/null +++ b/test/junit/scala/reflect/internal/util/SourceFileTest.scala @@ -0,0 +1,55 @@ +package scala.reflect.internal.util + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(classOf[JUnit4]) +class SourceFileTest { + def lineContentOf(code: String, offset: Int) = + Position.offset(new BatchSourceFile("", code), offset).lineContent + + @Test + def si8205_overflow(): Unit = { + val file = new BatchSourceFile("", "code no newline") + // the bug in lineToString counted until MaxValue, and the AIOOBE came from here + assertFalse(file.isEndOfLine(Int.MaxValue)) + } + + @Test + def si8205_lineToString(): Unit = { + assertEquals("", lineContentOf("", 0)) + assertEquals("abc", lineContentOf("abc", 0)) + assertEquals("abc", lineContentOf("abc", 3)) + assertEquals("code no newline", lineContentOf("code no newline", 1)) + assertEquals("", lineContentOf("\n", 0)) + assertEquals("abc", lineContentOf("abc\ndef", 0)) + assertEquals("abc", lineContentOf("abc\ndef", 3)) + assertEquals("def", lineContentOf("abc\ndef", 4)) + assertEquals("def", lineContentOf("abc\ndef", 6)) + assertEquals("def", lineContentOf("abc\ndef\n", 7)) + } + + @Test + def CRisEOL(): Unit = { + assertEquals("", lineContentOf("\r", 0)) + assertEquals("abc", lineContentOf("abc\rdef", 0)) + assertEquals("abc", lineContentOf("abc\rdef", 3)) + assertEquals("def", lineContentOf("abc\rdef", 4)) + assertEquals("def", lineContentOf("abc\rdef", 6)) + assertEquals("def", lineContentOf("abc\rdef\r", 7)) + } + + @Test + def CRNLisEOL(): Unit = { + assertEquals("", lineContentOf("\r\n", 0)) + assertEquals("abc", lineContentOf("abc\r\ndef", 0)) + assertEquals("abc", lineContentOf("abc\r\ndef", 3)) + assertEquals("abc", lineContentOf("abc\r\ndef", 4)) + assertEquals("def", lineContentOf("abc\r\ndef", 5)) + assertEquals("def", lineContentOf("abc\r\ndef", 7)) + assertEquals("def", lineContentOf("abc\r\ndef", 8)) + assertEquals("def", lineContentOf("abc\r\ndef\r\n", 9)) + } +} diff --git a/test/scaladoc/resources/SI-4014_0.scala b/test/scaladoc/resources/SI-4014_0.scala new file mode 100644 index 0000000000..c398fcc1e0 --- /dev/null +++ b/test/scaladoc/resources/SI-4014_0.scala @@ -0,0 +1,4 @@ +/** A template without authors. + * + */ +trait Foo
\ No newline at end of file diff --git a/test/scaladoc/resources/SI-4014_1.scala b/test/scaladoc/resources/SI-4014_1.scala new file mode 100644 index 0000000000..34386b515e --- /dev/null +++ b/test/scaladoc/resources/SI-4014_1.scala @@ -0,0 +1,5 @@ +/** A template with one author. + * + * @author The Only Author + */ +trait Foo
\ No newline at end of file diff --git a/test/scaladoc/resources/SI-4014_2.scala b/test/scaladoc/resources/SI-4014_2.scala new file mode 100644 index 0000000000..514f7a1e4c --- /dev/null +++ b/test/scaladoc/resources/SI-4014_2.scala @@ -0,0 +1,6 @@ +/** A template with more than one author. + * + * @author The First Author + * @author The Second Author + */ +trait Foo
\ No newline at end of file diff --git a/test/scaladoc/run/t7124.check b/test/scaladoc/run/t7124.check new file mode 100644 index 0000000000..96b627a322 --- /dev/null +++ b/test/scaladoc/run/t7124.check @@ -0,0 +1,3 @@ +List() +List(Paragraph(Text(macro))) +Done. diff --git a/test/scaladoc/run/t7124.scala b/test/scaladoc/run/t7124.scala new file mode 100644 index 0000000000..e8272000d2 --- /dev/null +++ b/test/scaladoc/run/t7124.scala @@ -0,0 +1,22 @@ +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + + override def code = """ + import scala.language.experimental.macros + class Test { + def print(): Unit = macro ??? + } + """ + + def scaladocSettings = "" + + def testModel(root: Package) = { + import access._ + val p = root._class("Test")._method("print") + + println(p.annotations) // no annotations + println(p.flags) // a 'macro' flag + } +} diff --git a/test/scaladoc/scalacheck/HtmlFactoryTest.scala b/test/scaladoc/scalacheck/HtmlFactoryTest.scala index 03348b81d2..56328ea875 100644 --- a/test/scaladoc/scalacheck/HtmlFactoryTest.scala +++ b/test/scaladoc/scalacheck/HtmlFactoryTest.scala @@ -47,6 +47,7 @@ object Test extends Properties("HtmlFactory") { settings.scaladocQuietRun = true settings.nowarn.value = true settings.classpath.value = getClasspath + settings.docAuthor.value = true val reporter = new scala.tools.nsc.reporters.ConsoleReporter(settings) new DocFactory(reporter, settings) @@ -563,12 +564,13 @@ object Test extends Properties("HtmlFactory") { property("Comment inheritance: Correct explicit inheritance for override") = checkText("explicit-inheritance-override.scala")( (Some("InheritDocDerived"), - """def function[T](arg1: T, arg2: String): Double + """def function[T](arg1: T, arg2: String): Double Starting line Starting line The base comment. And another sentence... The base comment. And another sentence... Ending line + Author: StartAuthor a Scala developer EndAuthor T StartT the type of the first argument EndT arg1 Start1 The T term comment End1 arg2 Start2 The string comment End2 @@ -589,12 +591,13 @@ object Test extends Properties("HtmlFactory") { property("Comment inheritance: Correct explicit inheritance for usecase") = checkText("explicit-inheritance-usecase.scala")( (Some("UseCaseInheritDoc"), - """def function[T](arg1: T, arg2: String): Double + """def function[T](arg1: T, arg2: String): Double [use case] Starting line [use case] Starting line The base comment. And another sentence... The base comment. And another sentence... Ending line + Author: StartAuthor a Scala developer EndAuthor T StartT the type of the first argument EndT arg1 Start1 The T term comment End1 arg2 Start2 The string comment End2 @@ -663,6 +666,45 @@ object Test extends Properties("HtmlFactory") { } } + property("SI-4014: Scaladoc omits @author: no authors") = { + val noAuthors = createTemplates("SI-4014_0.scala")("Foo.html") + + noAuthors match { + case node: scala.xml.Node => { + val s = node.toString + ! s.contains("Author") + } + case _ => false + } + } + + property("SI-4014: Scaladoc omits @author: one author") = { + val oneAuthor = createTemplates("SI-4014_1.scala")("Foo.html") + + oneAuthor match { + case node: scala.xml.Node => { + val s = node.toString + s.contains("<h6>Author:</h6>") + s.contains("<p>The Only Author\n</p>") + } + case _ => false + } + } + + property("SI-4014: Scaladoc omits @author: two authors") = { + val twoAuthors = createTemplates("SI-4014_2.scala")("Foo.html") + + twoAuthors match { + case node: scala.xml.Node => { + val s = node.toString + s.contains("<h6>Authors:</h6>") + s.contains("<p>The First Author\n</p>") + s.contains("<p>The Second Author\n</p>") + } + case _ => false + } + } + { val files = createTemplates("basic.scala") //println(files) diff --git a/versions.properties b/versions.properties index 62ba7ac379..2ea8e713f1 100644 --- a/versions.properties +++ b/versions.properties @@ -1,15 +1,16 @@ -starr.version=2.11.0-M7 +#Sun, 19 Jan 2014 23:57:57 +0100 +starr.version=2.11.0-M8 starr.use.released=1 # These are the versions of the modules that go with this release. # These properties are used during PR validation and in dbuild builds. -scala.binary.version=2.11.0-M7 +scala.binary.version=2.11.0-M8 # external modules shipped with distribution: scala-xml.version.number=1.0.0-RC7 scala-parser-combinators.version.number=1.0.0-RC5 -scala-continuations-plugin.version.number=1.0.0-RC2 -scala-continuations-library.version.number=1.0.0-RC2 +scala-continuations-plugin.version.number=1.0.0-RC3 +scala-continuations-library.version.number=1.0.0-RC3 scala-swing.version.number=1.0.0-RC2 # these ship with distribution (and scala-library-all depends on them) @@ -18,7 +19,7 @@ actors-migration.version.number=1.0.0 # external modules, used internally (not shipped) partest.version.number=1.0.0-RC8 -scalacheck.version.number=1.11.1 +scalacheck.version.number=1.11.3 # TODO: modularize the compiler #scala-compiler-doc.version.number=1.0.0-RC1 |