diff options
167 files changed, 2188 insertions, 952 deletions
@@ -1,7 +1,74 @@ -Aleksandar Prokopec <aleksandar@aleksandar-Latitude-E6500.(none)> -Aleksandar Prokopec <aleksandar@htpc.(none)> -Aleksandar Prokopec <aleksandar@htpc-axel22.(none)> -Aleksandar Prokopec <aleksandar@lampmac14.epfl.ch> +Adriaan Moors <adriaan.moors@typesafe.com> +Adriaan Moors <adriaan.moors@typesafe.com> <adriaan.moors@epfl.ch> +Adriaan Moors <adriaan.moors@typesafe.com> <adriaanm@gmail.com> Aleksandar Prokopec <aleksandar.prokopec@epfl.ch> -Daniel C. Sobral <dcs@dcs-132-CK-NF79.(none)> +Aleksandar Prokopec <aleksandar.prokopec@epfl.ch> <aleksandar.prokopec@gmail.com> +Aleksandar Prokopec <aleksandar.prokopec@epfl.ch> <aleksandar@aleksandar-Latitude-E6500.(none)> +Aleksandar Prokopec <aleksandar.prokopec@epfl.ch> <aleksandar@htpc-axel22.(none)> +Aleksandar Prokopec <aleksandar.prokopec@epfl.ch> <aleksandar@htpc.(none)> +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> +Antonio Cunei <antonio.cunei@typesafe.com> +Antonio Cunei <antonio.cunei@typesafe.com> <antonio.cunei@epfl.ch> +Buraq Emir <buraq@epfl.ch> +Caoyuan Deng <dcaoyuan@epfl.ch> +Chris Hodapp <clhodapp1@gmail.com> +Chris James <chrisJames@epfl.ch> +Christopher Vogt <vogt@epfl.ch> +Christopher Vogt <vogt@epfl.ch> <christopher.vogt@epfl.ch> +Christopher Vogt <vogt@epfl.ch> <github.com.nsp@cvogt.org> +Damien Obristi <damien.obrist@gmail.com> +Daniel C. Sobral <dcsobral@gmail.com> +Daniel C. Sobral <dcsobral@gmail.com> <dcs@dcs-132-CK-NF79.(none)> +Daniel Lorch <lorch@epfl.ch> +Erik Stenman <stenman@epfl.ch> +Eugene Burmako <xeno.by@gmail.com> +Eugene Burmako <xeno.by@gmail.com> <burmako@epfl.ch> +Eugene Vigdorchik <eugenevigdorchik@epfl.ch> <eugene.vigdorchik@gmail.com> +Geoff Reedy <geoff@programmer-monk.net> <gereedy@sandia.gov> +Ilya Sergei <ilyas@epfl.ch> +Ingo Maier <ingo.maier@epfl.ch> +Ingo Maier <ingo.maier@epfl.ch> <ingoem@gmail.com> +Josh Suereth <joshua.suereth@gmail.com> +Josh Suereth <joshua.suereth@gmail.com> <Joshua.Suereth@gmail.com> +Julien Eberle <jeberle@epfl.ch> +Kenji Yoshida <6b656e6a69@gmail.com> +Luc Bourlier <luc.bourlier@typesafe.com> +Luc Bourlier <luc.bourlier@typesafe.com> <skyluc@epfl.ch> +Luc Bourlier <skyluc@epfl.ch> +Martin Odersky <odersky@gmail.com> +Martin Odersky <odersky@gmail.com> <odersky@gamil.com> +Michael Pradel <pradel@epfl.ch> +Michel Schinz <schinz@epfl.ch> +Miguel Garcia <magarcia@epfl.ch> +Miguel Garcia <magarcia@epfl.ch> <miguelalfredo.garcia@epfl.ch> +Mirco Dotta <mirco.dotta@typesafe.com> +Mirco Dotta <mirco.dotta@typesafe.com> <mirco.dotta@gmail.com> +Moez A. Abdel-Gawad <moez@epfl.ch> +Mohsen Lesani <lesani@epfl.ch> +Nada Amin <amin@epfl.ch> +Nada Amin <amin@epfl.ch> <nada.amin@epfl.ch> +Nada Amin <amin@epfl.ch> <namin@alum.mit.edu> +Natallie Baikevich <lu-a-jalla@ya.ru> +Nikolay Mihaylov <mihaylov@epfl.ch> +Paolo Giarrusso <p.giarrusso@gmail.com> Pavel Pavlov <pavel.e.pavlov@gmail.com> +Philipp Haller <philipp.haller@typesafe.com> +Philipp Haller <philipp.haller@typesafe.com> <hallerp@gmail.com> +Philippe Altherr <paltherr@epfl.ch> +Raphaël Noir <noir@epfl.ch> +Roland Kuhn <rk@rkuhn.info> +Rüdiger Klaehn <rklaehn@gmail.com> +Sebastian Hack <shack@epfl.ch> +Simon Ochsenreither <simon@ochsenreither.de> +Stepan Koltsov <stepancheg@epfl.ch> +Stéphane Micheloud <michelou@epfl.ch> +Unknown Committer <lost.soul@typesafe.com> +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> +Vojin Jovanovic <vojin.jovanovic@epfl.ch> +Vojin Jovanovic <vojin.jovanovic@epfl.ch> <gvojin@gmail.com> @@ -2503,6 +2503,7 @@ Binary compatibility testing </artifact:dependencies> <artifact:dependencies pathId="old.bc.classpath"> <dependency groupId="org.scala-lang" artifactId="scala-library" version="2.10.0-RC2"/> + <dependency groupId="org.scala-lang" artifactId="scala-reflect" version="2.10.0-RC2"/> </artifact:dependencies> </target> @@ -2518,7 +2519,19 @@ Binary compatibility testing <classpath> <path refid="mima.classpath"/> </classpath> - </java> + </java> + <java + fork="true" + failonerror="true" + classname="com.typesafe.tools.mima.cli.Main"> + <arg value="--prev"/> + <arg value="${org.scala-lang:scala-reflect:jar}"/> + <arg value="--curr"/> + <arg value="${build-pack.dir}/lib/scala-reflect.jar"/> + <classpath> + <path refid="mima.classpath"/> + </classpath> + </java> </target> diff --git a/src/compiler/scala/tools/nsc/Driver.scala b/src/compiler/scala/tools/nsc/Driver.scala index b5fd20e1cc..fc247600f6 100644 --- a/src/compiler/scala/tools/nsc/Driver.scala +++ b/src/compiler/scala/tools/nsc/Driver.scala @@ -54,10 +54,10 @@ abstract class Driver { doCompile(compiler) } catch { case ex: Throwable => - compiler.logThrowable(ex) + compiler.reportThrowable(ex) ex match { - case FatalError(msg) => reporter.error(null, "fatal error: " + msg) - case _ => throw ex + case FatalError(msg) => // signals that we should fail compilation. + case _ => throw ex // unexpected error, tell the outside world. } } } diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 34d5d10cbf..95da7324aa 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -284,7 +284,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) log(msg) } - def logThrowable(t: Throwable): Unit = globalError(throwableAsString(t)) + @deprecated("Renamed to reportThrowable", "2.10.1") + def logThrowable(t: Throwable): Unit = reportThrowable(t) + def reportThrowable(t: Throwable): Unit = globalError(throwableAsString(t)) override def throwableAsString(t: Throwable) = util.stackTraceString(t) // ------------ File interface ----------------------------------------- @@ -572,7 +574,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val runsRightAfter = None } with Inliners - // phaseName = "inlineExceptionHandlers" + // phaseName = "inlinehandlers" object inlineExceptionHandlers extends { val global: Global.this.type = Global.this val runsAfter = List("inliner") @@ -582,7 +584,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // phaseName = "closelim" object closureElimination extends { val global: Global.this.type = Global.this - val runsAfter = List("inlineExceptionHandlers") + val runsAfter = List("inlinehandlers") val runsRightAfter = None } with ClosureElimination @@ -709,7 +711,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /* The set of phase objects that is the basis for the compiler phase chain */ protected lazy val phasesSet = new mutable.HashSet[SubComponent] protected lazy val phasesDescMap = new mutable.HashMap[SubComponent, String] withDefaultValue "" - private lazy val phaseTimings = new Phases.TimingModel // tracking phase stats protected def addToPhasesSet(sub: SubComponent, descr: String) { phasesSet += sub @@ -724,13 +725,41 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** A description of the phases that will run */ def phaseDescriptions: String = { - val width = phaseNames map (_.length) max - val fmt = "%" + width + "s %2s %s\n" + val Limit = 16 // phase names should not be absurdly long + val MaxCol = 80 // because some of us edit on green screens + val maxName = (0 /: phaseNames)(_ max _.length) + val width = maxName min Limit + val maxDesc = MaxCol - (width + 6) // descriptions not novels + val fmt = if (settings.verbose.value) s"%${maxName}s %2s %s%n" + else s"%${width}.${width}s %2s %.${maxDesc}s%n" val line1 = fmt.format("phase name", "id", "description") val line2 = fmt.format("----------", "--", "-----------") + + // built-in string precision merely truncates + import java.util.{ Formattable, FormattableFlags, Formatter } + def fmtable(s: String) = new Formattable { + override def formatTo(formatter: Formatter, flags: Int, width: Int, precision: Int) { + val p = elliptically(s, precision) + val w = if (width > 0 && p.length < width) { + import FormattableFlags.LEFT_JUSTIFY + val leftly = (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY + val sb = new StringBuilder + def pad() = 1 to width - p.length foreach (_ => sb.append(' ')) + if (!leftly) pad() + sb.append(p) + if (leftly) pad() + sb.toString + } else p + formatter.out.append(w) + } + } + def elliptically(s: String, max: Int) = + if (max < 0 || s.length <= max) s + else if (max < 4) s.take(max) + else s.take(max - 3) + "..." val descs = phaseDescriptors.zipWithIndex map { - case (ph, idx) => fmt.format(ph.phaseName, idx + 1, phasesDescMap(ph)) + case (ph, idx) => fmt.format(fmtable(ph.phaseName), idx + 1, fmtable(phasesDescMap(ph))) } line1 :: line2 :: descs mkString } @@ -1038,37 +1067,41 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Don't want to introduce new errors trying to report errors, * so swallow exceptions. */ - override def supplementErrorMessage(errorMessage: String): String = try { - val tree = analyzer.lastTreeToTyper - val sym = tree.symbol - val tpe = tree.tpe - val enclosing = lastSeenContext.enclClassOrMethod.tree - - val info1 = formatExplain( - "while compiling" -> currentSource.path, - "during phase" -> ( if (globalPhase eq phase) phase else "global=%s, enteringPhase=%s".format(globalPhase, phase) ), - "library version" -> scala.util.Properties.versionString, - "compiler version" -> Properties.versionString, - "reconstructed args" -> settings.recreateArgs.mkString(" ") - ) - val info2 = formatExplain( - "last tree to typer" -> tree.summaryString, - "symbol" -> Option(sym).fold("null")(_.debugLocationString), - "symbol definition" -> Option(sym).fold("null")(_.defString), - "tpe" -> tpe, - "symbol owners" -> ownerChainString(sym), - "context owners" -> ownerChainString(lastSeenContext.owner) - ) - val info3: List[String] = ( - ( List("== Enclosing template or block ==", nodePrinters.nodeToString(enclosing).trim) ) - ++ ( if (tpe eq null) Nil else List("== Expanded type of tree ==", typeDeconstruct.show(tpe)) ) - ++ ( if (!settings.debug.value) Nil else List("== Current unit body ==", nodePrinters.nodeToString(currentUnit.body)) ) - ++ ( List(errorMessage) ) - ) - - ("\n" + info1) :: info2 :: info3 mkString "\n\n" - } - catch { case x: Exception => errorMessage } + override def supplementErrorMessage(errorMessage: String): String = + if (currentRun.supplementedError) errorMessage + else try { + val tree = analyzer.lastTreeToTyper + val sym = tree.symbol + val tpe = tree.tpe + val enclosing = lastSeenContext.enclClassOrMethod.tree + + val info1 = formatExplain( + "while compiling" -> currentSource.path, + "during phase" -> ( if (globalPhase eq phase) phase else "global=%s, enteringPhase=%s".format(globalPhase, phase) ), + "library version" -> scala.util.Properties.versionString, + "compiler version" -> Properties.versionString, + "reconstructed args" -> settings.recreateArgs.mkString(" ") + ) + val info2 = formatExplain( + "last tree to typer" -> tree.summaryString, + "symbol" -> Option(sym).fold("null")(_.debugLocationString), + "symbol definition" -> Option(sym).fold("null")(_.defString), + "tpe" -> tpe, + "symbol owners" -> ownerChainString(sym), + "context owners" -> ownerChainString(lastSeenContext.owner) + ) + val info3: List[String] = ( + ( List("== Enclosing template or block ==", nodePrinters.nodeToString(enclosing).trim) ) + ++ ( if (tpe eq null) Nil else List("== Expanded type of tree ==", typeDeconstruct.show(tpe)) ) + ++ ( if (!settings.debug.value) Nil else List("== Current unit body ==", nodePrinters.nodeToString(currentUnit.body)) ) + ++ ( List(errorMessage) ) + ) + + currentRun.supplementedError = true + + ("\n" + info1) :: info2 :: info3 mkString "\n\n" + } + catch { case x: Exception => errorMessage } /** The id of the currently active run */ @@ -1122,6 +1155,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Has any macro expansion used a fallback during this run? */ var seenMacroExpansionsFallingBack = false + /** Have we already supplemented the error message of a compiler crash? */ + private[nsc] final var supplementedError = false + private val unitbuf = new mutable.ListBuffer[CompilationUnit] val compiledFiles = new mutable.HashSet[String] @@ -1302,7 +1338,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val cleanupPhase = phaseNamed("cleanup") val icodePhase = phaseNamed("icode") val inlinerPhase = phaseNamed("inliner") - val inlineExceptionHandlersPhase = phaseNamed("inlineExceptionHandlers") + val inlineExceptionHandlersPhase = phaseNamed("inlinehandlers") val closelimPhase = phaseNamed("closelim") val dcePhase = phaseNamed("dce") // val jvmPhase = phaseNamed("jvm") @@ -1478,7 +1514,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // progress update informTime(globalPhase.description, startTime) - phaseTimings(globalPhase) = currentTime - startTime val shouldWriteIcode = ( (settings.writeICode.isSetByUser && (settings.writeICode containsPhase globalPhase)) || (!settings.Xprint.doAllPhases && (settings.Xprint containsPhase globalPhase) && runIsAtOptimiz) diff --git a/src/compiler/scala/tools/nsc/Phases.scala b/src/compiler/scala/tools/nsc/Phases.scala index 1266622b6d..e379afce9b 100644 --- a/src/compiler/scala/tools/nsc/Phases.scala +++ b/src/compiler/scala/tools/nsc/Phases.scala @@ -8,6 +8,7 @@ package scala.tools.nsc import scala.reflect.internal.util.TableDef import scala.language.postfixOps +@deprecated("Scheduled for removal as being a dead-code in the compiler.", "2.10.1") object Phases { val MaxPhases = 64 diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala index 023f3c229c..c9bf131b79 100755 --- a/src/compiler/scala/tools/nsc/ast/DocComments.scala +++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala @@ -16,11 +16,22 @@ import scala.collection.mutable */ trait DocComments { self: Global => - var cookedDocComments = Map[Symbol, String]() + val cookedDocComments = mutable.HashMap[Symbol, String]() /** The raw doc comment map */ val docComments = mutable.HashMap[Symbol, DocComment]() + def clearDocComments() { + cookedDocComments.clear() + docComments.clear() + defs.clear() + } + + /** Associate comment with symbol `sym` at position `pos`. */ + def docComment(sym: Symbol, docStr: String, pos: Position = NoPosition) = + if ((sym ne null) && (sym ne NoSymbol)) + docComments += (sym -> DocComment(docStr, pos)) + /** The raw doc comment of symbol `sym`, as it appears in the source text, "" if missing. */ def rawDocComment(sym: Symbol): String = @@ -47,25 +58,20 @@ trait DocComments { self: Global => * If a symbol does not have a doc comment but some overridden version of it does, * the doc comment of the overridden version is copied instead. */ - def cookedDocComment(sym: Symbol, docStr: String = ""): String = cookedDocComments.get(sym) match { - case Some(comment) => - comment - case None => - val ownComment = if (docStr.length == 0) docComments get sym map (_.template) getOrElse "" + def cookedDocComment(sym: Symbol, docStr: String = ""): String = cookedDocComments.getOrElseUpdate(sym, { + val ownComment = if (docStr.length == 0) docComments get sym map (_.template) getOrElse "" else DocComment(docStr).template - val comment = superComment(sym) match { - case None => - if (ownComment.indexOf("@inheritdoc") != -1) - reporter.warning(sym.pos, "The comment for " + sym + - " contains @inheritdoc, but no parent comment is available to inherit from.") - ownComment.replaceAllLiterally("@inheritdoc", "<invalid inheritdoc annotation>") - case Some(sc) => - if (ownComment == "") sc - else expandInheritdoc(sc, merge(sc, ownComment, sym), sym) - } - cookedDocComments += (sym -> comment) - comment - } + superComment(sym) match { + case None => + if (ownComment.indexOf("@inheritdoc") != -1) + reporter.warning(sym.pos, "The comment for " + sym + + " contains @inheritdoc, but no parent comment is available to inherit from.") + ownComment.replaceAllLiterally("@inheritdoc", "<invalid inheritdoc annotation>") + case Some(sc) => + if (ownComment == "") sc + else expandInheritdoc(sc, merge(sc, ownComment, sym), sym) + } + }) /** The cooked doc comment of symbol `sym` after variable expansion, or "" if missing. * diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 0e3e2fe644..4b5e23e177 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -343,9 +343,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => if (tpt.original != null) transform(tpt.original) else if (tpt.tpe != null && (tpt.wasEmpty || (tpt.tpe exists (tp => locals contains tp.typeSymbol)))) { - val dupl = tpt.duplicate - dupl.tpe = null - dupl + tpt.duplicate.clearType() } else tree case TypeApply(fn, args) if args map transform exists (_.isEmpty) => @@ -356,8 +354,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => val dupl = tree.duplicate if (tree.hasSymbolField && (!localOnly || (locals contains tree.symbol)) && !(keepLabels && tree.symbol.isLabel)) dupl.symbol = NoSymbol - dupl.tpe = null - dupl + dupl.clearType() } } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 76d7af7cc6..744644fd49 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2153,8 +2153,8 @@ self => val start = in.offset newLineOptWhenFollowedBy(LPAREN) if (ofCaseClass && in.token != LPAREN) - deprecationWarning(in.lastOffset, "case classes without a parameter list have been deprecated;\n"+ - "use either case objects or case classes with `()' as parameter list.") + syntaxError(in.lastOffset, "case classes without a parameter list are not allowed;\n"+ + "use either case objects or case classes with an explicit `()' as a parameter list.") while (implicitmod == 0 && in.token == LPAREN) { in.nextToken() vds += paramClause() diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala index 34bdc1ede4..24c18e6530 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala @@ -308,7 +308,12 @@ trait BasicBlocks { else instrs.zipWithIndex collect { case (oldInstr, i) if map contains oldInstr => - code.touched |= replaceInstruction(i, map(oldInstr)) + // SI-6288 clone important here because `replaceInstruction` assigns + // a position to `newInstr`. Without this, a single instruction can + // be added twice, and the position last position assigned clobbers + // all previous positions in other usages. + val newInstr = map(oldInstr).clone() + code.touched |= replaceInstruction(i, newInstr) } ////////////////////// Emit ////////////////////// diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index cc3562079e..2ea26ddaa9 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1643,9 +1643,7 @@ abstract class GenICode extends SubComponent { t match { case t @ Apply(_, args) if sym.isLabel && !boundLabels(sym) => val newSym = getLabel(sym.pos, sym.name) - val tree = Apply(global.gen.mkAttributedRef(newSym), transformTrees(args)) setPos t.pos - tree.tpe = t.tpe - tree + Apply(global.gen.mkAttributedRef(newSym), transformTrees(args)) setPos t.pos setType t.tpe case t @ LabelDef(name, params, rhs) => val newSym = getLabel(t.pos, name) diff --git a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala index c534c2230c..4e65c72b0b 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala @@ -52,7 +52,7 @@ abstract class InlineExceptionHandlers extends SubComponent { import icodes._ import icodes.opcodes._ - val phaseName = "inlineExceptionHandlers" + val phaseName = "inlinehandlers" /** Create a new phase */ override def newPhase(p: Phase) = new InlineExceptionHandlersPhase(p) diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala index a091bc3e62..77e53bd90b 100644 --- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala @@ -78,7 +78,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor with model.ModelFactoryImplicitSupport with model.ModelFactoryTypeSupport with model.diagram.DiagramFactory - with model.comment.CommentFactory + with model.CommentFactory with model.TreeFactory with model.MemberLookup { override def templateShouldDocument(sym: compiler.Symbol, inTpl: DocTemplateImpl) = diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/base/CommentFactoryBase.scala index c798def4cb..30f33e48c9 100644..100755 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/base/CommentFactoryBase.scala @@ -1,13 +1,13 @@ /* NSC -- new Scala compiler - * Copyright 2007-2013 LAMP/EPFL + * Copyright 2007-2012 LAMP/EPFL * @author Manohar Jonnalagedda */ package scala.tools.nsc package doc -package model -package comment +package base +import base.comment._ import scala.collection._ import scala.util.matching.Regex import scala.reflect.internal.util.Position @@ -21,73 +21,10 @@ import scala.language.postfixOps * * @author Manohar Jonnalagedda * @author Gilles Dubochet */ -trait CommentFactory { thisFactory: ModelFactory with CommentFactory with MemberLookup=> +trait CommentFactoryBase { this: MemberLookupBase => val global: Global - import global.{ reporter, definitions } - - protected val commentCache = mutable.HashMap.empty[(global.Symbol, TemplateImpl), Comment] - - def comment(sym: global.Symbol, currentTpl: Option[DocTemplateImpl], inTpl: DocTemplateImpl): Option[Comment] = { - val key = (sym, inTpl) - if (commentCache isDefinedAt key) - Some(commentCache(key)) - else { - val c = defineComment(sym, currentTpl, inTpl) - if (c isDefined) commentCache += (sym, inTpl) -> c.get - c - } - } - - /** A comment is usualy created by the parser, however for some special - * cases we have to give some `inTpl` comments (parent class for example) - * to the comment of the symbol. - * This function manages some of those cases : Param accessor and Primary constructor */ - def defineComment(sym: global.Symbol, currentTpl: Option[DocTemplateImpl], inTpl: DocTemplateImpl):Option[Comment] = { - - //param accessor case - // We just need the @param argument, we put it into the body - if( sym.isParamAccessor && - inTpl.comment.isDefined && - inTpl.comment.get.valueParams.isDefinedAt(sym.encodedName)) { - val comContent = Some(inTpl.comment.get.valueParams(sym.encodedName)) - Some(createComment(body0 = comContent)) - } - - // Primary constructor case - // We need some content of the class definition : @constructor for the body, - // @param and @deprecated, we can add some more if necessary - else if (sym.isPrimaryConstructor && inTpl.comment.isDefined ) { - val tplComment = inTpl.comment.get - // If there is nothing to put into the comment there is no need to create it - if(tplComment.constructor.isDefined || - tplComment.throws != Map.empty || - tplComment.valueParams != Map.empty || - tplComment.typeParams != Map.empty || - tplComment.deprecated.isDefined - ) - Some(createComment( body0 = tplComment.constructor, - throws0 = tplComment.throws, - valueParams0 = tplComment.valueParams, - typeParams0 = tplComment.typeParams, - deprecated0 = tplComment.deprecated - )) - else None - } - - //other comment cases - // parse function will make the comment - else { - val rawComment = global.expandedDocComment(sym, inTpl.sym).trim - if (rawComment != "") { - val tplOpt = if (currentTpl.isDefined) currentTpl else Some(inTpl) - val c = parse(rawComment, global.rawDocComment(sym), global.docCommentPos(sym), tplOpt) - Some(c) - } - else None - } - - } + import global.{ reporter, Symbol } /* Creates comments with necessary arguments */ def createComment ( @@ -251,9 +188,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member * @param comment The expanded comment string (including start and end markers) to be parsed. * @param src The raw comment source string. * @param pos The position of the comment in source. */ - protected def parse(comment: String, src: String, pos: Position, inTplOpt: Option[DocTemplateImpl] = None): Comment = { - assert(!inTplOpt.isDefined || inTplOpt.get != null) - + protected def parseAtSymbol(comment: String, src: String, pos: Position, siteOpt: Option[Symbol] = None): Comment = { /** The cleaned raw comment as a list of lines. Cleaning removes comment * start and end markers, line start markers and unnecessary whitespace. */ def clean(comment: String): List[String] = { @@ -379,7 +314,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member val tagsWithoutDiagram = tags.filterNot(pair => stripTags.contains(pair._1)) val bodyTags: mutable.Map[TagKey, List[Body]] = - mutable.Map(tagsWithoutDiagram mapValues {tag => tag map (parseWiki(_, pos, inTplOpt))} toSeq: _*) + mutable.Map(tagsWithoutDiagram mapValues {tag => tag map (parseWikiAtSymbol(_, pos, siteOpt))} toSeq: _*) def oneTag(key: SimpleTagKey): Option[Body] = ((bodyTags remove key): @unchecked) match { @@ -412,7 +347,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member } val com = createComment ( - body0 = Some(parseWiki(docBody.toString, pos, inTplOpt)), + body0 = Some(parseWikiAtSymbol(docBody.toString, pos, siteOpt)), authors0 = allTags(SimpleTagKey("author")), see0 = allTags(SimpleTagKey("see")), result0 = oneTag(SimpleTagKey("return")), @@ -452,20 +387,14 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member * - Removed start-of-line star and one whitespace afterwards (if present). * - Removed all end-of-line whitespace. * - Only `endOfLine` is used to mark line endings. */ - def parseWiki(string: String, pos: Position, inTplOpt: Option[DocTemplateImpl]): Body = { - assert(!inTplOpt.isDefined || inTplOpt.get != null) - - new WikiParser(string, pos, inTplOpt).document() - } + def parseWikiAtSymbol(string: String, pos: Position, siteOpt: Option[Symbol]): Body = new WikiParser(string, pos, siteOpt).document() /** TODO * * @author Ingo Maier * @author Manohar Jonnalagedda * @author Gilles Dubochet */ - protected final class WikiParser(val buffer: String, pos: Position, inTplOpt: Option[DocTemplateImpl]) extends CharReader(buffer) { wiki => - assert(!inTplOpt.isDefined || inTplOpt.get != null) - + protected final class WikiParser(val buffer: String, pos: Position, siteOpt: Option[Symbol]) extends CharReader(buffer) { wiki => var summaryParsed = false def document(): Body = { @@ -752,6 +681,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member val SchemeUri = """([a-z]+:.*)""".r jump("[[") val parens = 2 + repeatJump('[') + val start = "[" * parens val stop = "]" * parens //println("link with " + parens + " matching parens") val target = readUntil { check(stop) || check(" ") } @@ -767,7 +697,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member case (SchemeUri(uri), optTitle) => Link(uri, optTitle getOrElse Text(uri)) case (qualName, optTitle) => - makeEntityLink(optTitle getOrElse Text(target), pos, target, inTplOpt) + makeEntityLink(optTitle getOrElse Text(target), pos, target, siteOpt) } } diff --git a/src/compiler/scala/tools/nsc/doc/base/LinkTo.scala b/src/compiler/scala/tools/nsc/doc/base/LinkTo.scala new file mode 100755 index 0000000000..c11179800c --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/base/LinkTo.scala @@ -0,0 +1,15 @@ +/* NSC -- new Scala compiler + * Copyright 2007-2013 LAMP/EPFL + */ + +package scala.tools.nsc +package doc +package base + +import scala.collection._ + +sealed trait LinkTo +final case class LinkToMember[Mbr, Tpl](mbr: Mbr, tpl: Tpl) extends LinkTo +final case class LinkToTpl[Tpl](tpl: Tpl) extends LinkTo +final case class LinkToExternal(name: String, url: String) extends LinkTo +final case class Tooltip(name: String) extends LinkTo diff --git a/src/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala b/src/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala new file mode 100755 index 0000000000..35390adcd9 --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala @@ -0,0 +1,229 @@ +package scala.tools.nsc +package doc +package base + +import comment._ + +/** This trait extracts all required information for documentation from compilation units. + * The base trait has been extracted to allow getting light-weight documentation + * for a particular symbol in the IDE.*/ +trait MemberLookupBase { + + val global: Global + val settings: doc.Settings + + import global._ + def internalLink(sym: Symbol, site: Symbol): Option[LinkTo] + def chooseLink(links: List[LinkTo]): LinkTo + def toString(link: LinkTo): String + + import global._ + import definitions.{ NothingClass, AnyClass, AnyValClass, AnyRefClass, ListClass } + import rootMirror.{RootPackage, EmptyPackage} + + private def isRoot(s: Symbol) = s.isRootSymbol || s.isEmptyPackage || s.isEmptyPackageClass + + def makeEntityLink(title: Inline, pos: Position, query: String, siteOpt: Option[Symbol]) = + new EntityLink(title) { lazy val link = memberLookup(pos, query, siteOpt) } + + private var showExplanation = true + private def explanation: String = + if (showExplanation) { + showExplanation = false + """ + |Quick crash course on using Scaladoc links + |========================================== + |Disambiguating terms and types: Prefix terms with '$' and types with '!' in case both names are in use: + | - [[scala.collection.immutable.List!.apply class List's apply method]] and + | - [[scala.collection.immutable.List$.apply object List's apply method]] + |Disambiguating overloaded members: If a term is overloaded, you can indicate the first part of its signature followed by *: + | - [[[scala.collection.immutable.List$.fill[A](Int)(⇒A):List[A]* Fill with a single parameter]]] + | - [[[scala.collection.immutable.List$.fill[A](Int,Int)(⇒A):List[List[A]]* Fill with a two parameters]]] + |Notes: + | - you can use any number of matching square brackets to avoid interference with the signature + | - you can use \\. to escape dots in prefixes (don't forget to use * at the end to match the signature!) + | - you can use \\# to escape hashes, otherwise they will be considered as delimiters, like dots.""".stripMargin + } else "" + + def memberLookup(pos: Position, query: String, siteOpt: Option[Symbol]): LinkTo = { + var members = breakMembers(query) + + // (1) First look in the root package, as most of the links are qualified + val fromRoot = lookupInRootPackage(pos, members) + + // (2) Or recursively go into each containing template. + val fromParents = siteOpt.fold(Stream.empty[Symbol]) { s => + Stream.iterate(s)(_.owner) + }.takeWhile (!isRoot(_)).map { + lookupInTemplate(pos, members, _) + } + + val syms = (fromRoot +: fromParents) find (!_.isEmpty) getOrElse Nil + + val links = syms flatMap { case (sym, site) => internalLink(sym, site) } match { + case Nil => + // (3) Look at external links + syms.flatMap { case (sym, owner) => + // reconstruct the original link + def linkName(sym: Symbol) = { + def nameString(s: Symbol) = s.nameString + (if ((s.isModule || s.isModuleClass) && !s.isPackage) "$" else "") + val packageSuffix = if (sym.isPackage) ".package" else "" + + sym.ownerChain.reverse.filterNot(isRoot(_)).map(nameString(_)).mkString(".") + packageSuffix + } + + if (sym.isClass || sym.isModule || sym.isTrait || sym.isPackage) + findExternalLink(sym, linkName(sym)) + else if (owner.isClass || owner.isModule || owner.isTrait || owner.isPackage) + findExternalLink(sym, linkName(owner) + "@" + externalSignature(sym)) + else + None + } + case links => links + } + links match { + case Nil => + if (!settings.docNoLinkWarnings.value) + reporter.warning(pos, "Could not find any member to link for \"" + query + "\".") + // (4) if we still haven't found anything, create a tooltip + Tooltip(query) + case List(l) => l + case links => + val chosen = chooseLink(links) + def linkToString(link: LinkTo) = { + val chosenInfo = + if (link == chosen) " [chosen]" else "" + toString(link) + chosenInfo + "\n" + } + if (!settings.docNoLinkWarnings.value) { + val allLinks = links.map(linkToString).mkString + reporter.warning(pos, + s"""The link target \"$query\" is ambiguous. Several members fit the target: + |$allLinks + |$explanation""".stripMargin) + } + chosen + } + } + + private sealed trait SearchStrategy + private case object BothTypeAndTerm extends SearchStrategy + private case object OnlyType extends SearchStrategy + private case object OnlyTerm extends SearchStrategy + + private def lookupInRootPackage(pos: Position, members: List[String]) = + lookupInTemplate(pos, members, EmptyPackage) ::: lookupInTemplate(pos, members, RootPackage) + + private def lookupInTemplate(pos: Position, members: List[String], container: Symbol): List[(Symbol, Symbol)] = { + // Maintaining compatibility with previous links is a bit tricky here: + // we have a preference for term names for all terms except for the last, where we prefer a class: + // How to do this: + // - at each step we do a DFS search with the prefered strategy + // - if the search doesn't return any members, we backtrack on the last decision + // * we look for terms with the last member's name + // * we look for types with the same name, all the way up + val result = members match { + case Nil => Nil + case mbrName::Nil => + var syms = lookupInTemplate(pos, mbrName, container, OnlyType) map ((_, container)) + if (syms.isEmpty) + syms = lookupInTemplate(pos, mbrName, container, OnlyTerm) map ((_, container)) + syms + + case tplName::rest => + def completeSearch(syms: List[Symbol]) = + syms flatMap (lookupInTemplate(pos, rest, _)) + + completeSearch(lookupInTemplate(pos, tplName, container, OnlyTerm)) match { + case Nil => completeSearch(lookupInTemplate(pos, tplName, container, OnlyType)) + case syms => syms + } + } + //println("lookupInTemplate(" + members + ", " + container + ") => " + result) + result + } + + private def lookupInTemplate(pos: Position, member: String, container: Symbol, strategy: SearchStrategy): List[Symbol] = { + val name = member.stripSuffix("$").stripSuffix("!").stripSuffix("*") + def signatureMatch(sym: Symbol): Boolean = externalSignature(sym).startsWith(name) + + // We need to cleanup the bogus classes created by the .class file parser. For example, [[scala.Predef]] resolves + // to (bogus) class scala.Predef loaded by the class loader -- which we need to eliminate by looking at the info + // and removing NoType classes + def cleanupBogusClasses(syms: List[Symbol]) = { syms.filter(_.info != NoType) } + + def syms(name: Name) = container.info.nonPrivateMember(name.encodedName).alternatives + def termSyms = cleanupBogusClasses(syms(newTermName(name))) + def typeSyms = cleanupBogusClasses(syms(newTypeName(name))) + + val result = if (member.endsWith("$")) + termSyms + else if (member.endsWith("!")) + typeSyms + else if (member.endsWith("*")) + cleanupBogusClasses(container.info.nonPrivateDecls) filter signatureMatch + else + strategy match { + case BothTypeAndTerm => termSyms ::: typeSyms + case OnlyType => typeSyms + case OnlyTerm => termSyms + } + + //println("lookupInTemplate(" + member + ", " + container + ") => " + result) + result + } + + private def breakMembers(query: String): List[String] = { + // Okay, how does this work? Well: you split on . but you don't want to split on \. => thus the ugly regex + // query.split((?<=[^\\\\])\\.).map(_.replaceAll("\\.")) + // The same code, just faster: + var members = List[String]() + var index = 0 + var last_index = 0 + val length = query.length + while (index < length) { + if ((query.charAt(index) == '.' || query.charAt(index) == '#') && + ((index == 0) || (query.charAt(index-1) != '\\'))) { + + val member = query.substring(last_index, index).replaceAll("\\\\([#\\.])", "$1") + // we want to allow javadoc-style links [[#member]] -- which requires us to remove empty members from the first + // elemnt in the list + if ((member != "") || (!members.isEmpty)) + members ::= member + last_index = index + 1 + } + index += 1 + } + if (last_index < length) + members ::= query.substring(last_index, length).replaceAll("\\\\\\.", ".") + members.reverse + } + + + def findExternalLink(sym: Symbol, name: String): Option[LinkToExternal] = { + val sym1 = + if (sym == AnyClass || sym == AnyRefClass || sym == AnyValClass || sym == NothingClass) ListClass + else if (sym.isPackage) + /* Get package object which has associatedFile ne null */ + sym.info.member(newTermName("package")) + else sym + Option(sym1.associatedFile) flatMap (_.underlyingSource) flatMap { src => + val path = src.path + settings.extUrlMapping get path map { url => + LinkToExternal(name, url + "#" + name) + } + } orElse { + // Deprecated option. + settings.extUrlPackageMapping find { + case (pkg, _) => name startsWith pkg + } map { + case (_, url) => LinkToExternal(name, url + "#" + name) + } + } + } + + def externalSignature(sym: Symbol) = { + sym.info // force it, otherwise we see lazy types + (sym.nameString + sym.signatureString).replaceAll("\\s", "") + } +} diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala b/src/compiler/scala/tools/nsc/doc/base/comment/Body.scala index 8848af95eb..2a07547de2 100644..100755 --- a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala +++ b/src/compiler/scala/tools/nsc/doc/base/comment/Body.scala @@ -5,7 +5,7 @@ package scala.tools.nsc package doc -package model +package base package comment import scala.collection._ diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala b/src/compiler/scala/tools/nsc/doc/base/comment/Comment.scala index 736727fc1a..a3d05ae50b 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala +++ b/src/compiler/scala/tools/nsc/doc/base/comment/Comment.scala @@ -5,7 +5,7 @@ package scala.tools.nsc package doc -package model +package base package comment import scala.collection._ @@ -128,5 +128,4 @@ abstract class Comment { (authors map ("@author " + _.toString)).mkString("\n") + (result map ("@return " + _.toString)).mkString("\n") + (version map ("@version " + _.toString)).mkString - } diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala index c898348526..829df97fc2 100644 --- a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala +++ b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala @@ -7,8 +7,9 @@ package scala.tools.nsc package doc package html +import base._ +import base.comment._ import model._ -import comment._ import scala.xml.NodeSeq import scala.xml.dtd.{DocType, PublicID} @@ -126,12 +127,12 @@ abstract class HtmlPage extends Page { thisPage => } def linkToHtml(text: Inline, link: LinkTo, hasLinks: Boolean) = link match { - case LinkToTpl(dtpl) => + case LinkToTpl(dtpl: TemplateEntity) => if (hasLinks) <a href={ relativeLinkTo(dtpl) } class="extype" name={ dtpl.qualifiedName }>{ inlineToHtml(text) }</a> else <span class="extype" name={ dtpl.qualifiedName }>{ inlineToHtml(text) }</span> - case LinkToMember(mbr, inTpl) => + case LinkToMember(mbr: MemberEntity, inTpl: TemplateEntity) => if (hasLinks) <a href={ relativeLinkTo(inTpl) + "#" + mbr.signature } class="extmbr" name={ mbr.qualifiedName }>{ inlineToHtml(text) }</a> else @@ -140,7 +141,7 @@ abstract class HtmlPage extends Page { thisPage => <span class="extype" name={ tooltip }>{ inlineToHtml(text) }</span> case LinkToExternal(name, url) => <a href={ url } class="extype" target="_top">{ inlineToHtml(text) }</a> - case NoLink => + case _ => inlineToHtml(text) } diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala index 3f40e2cd0a..ff64fb4c0f 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -8,6 +8,11 @@ package doc package html package page +import base._ +import base.comment._ + +import model._ +import model.diagram._ import scala.xml.{ NodeSeq, Text, UnprefixedAttribute } import scala.language.postfixOps @@ -328,12 +333,10 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp } } - def memberToShortCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = { - if (mbr.comment.isEmpty) - NodeSeq.Empty - else - <p class="shortcomment cmt">{ memberToUseCaseCommentHtml(mbr, isSelf) }{ inlineToHtml(mbr.comment.get.short) }</p> - } + def memberToShortCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = + mbr.comment.fold(NodeSeq.Empty) { comment => + <p class="shortcomment cmt">{ memberToUseCaseCommentHtml(mbr, isSelf) }{ inlineToHtml(comment.short) }</p> + } def memberToInlineCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = <p class="comment cmt">{ inlineToHtml(mbr.comment.get.short) }</p> @@ -354,37 +357,34 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp case _ => Nil } - def mbrCmt = mbr.comment.get - - def paramCommentToHtml(prs: List[ParameterEntity]): NodeSeq = prs match { + def paramCommentToHtml(prs: List[ParameterEntity], comment: Comment): NodeSeq = prs match { case (tp: TypeParam) :: rest => val paramEntry: NodeSeq = { - <dt class="tparam">{ tp.name }</dt><dd class="cmt">{ bodyToHtml(mbrCmt.typeParams(tp.name)) }</dd> + <dt class="tparam">{ tp.name }</dt><dd class="cmt">{ bodyToHtml(comment.typeParams(tp.name)) }</dd> } - paramEntry ++ paramCommentToHtml(rest) + paramEntry ++ paramCommentToHtml(rest, comment) case (vp: ValueParam) :: rest => val paramEntry: NodeSeq = { - <dt class="param">{ vp.name }</dt><dd class="cmt">{ bodyToHtml(mbrCmt.valueParams(vp.name)) }</dd> + <dt class="param">{ vp.name }</dt><dd class="cmt">{ bodyToHtml(comment.valueParams(vp.name)) }</dd> } - paramEntry ++ paramCommentToHtml(rest) + paramEntry ++ paramCommentToHtml(rest, comment) case _ => NodeSeq.Empty } - if (mbr.comment.isEmpty) NodeSeq.Empty - else { + mbr.comment.fold(NodeSeq.Empty) { comment => val cmtedPrs = prs filter { - case tp: TypeParam => mbrCmt.typeParams isDefinedAt tp.name - case vp: ValueParam => mbrCmt.valueParams isDefinedAt vp.name + case tp: TypeParam => comment.typeParams isDefinedAt tp.name + case vp: ValueParam => comment.valueParams isDefinedAt vp.name } - if (cmtedPrs.isEmpty && mbrCmt.result.isEmpty) NodeSeq.Empty + if (cmtedPrs.isEmpty && comment.result.isEmpty) NodeSeq.Empty else { <dl class="paramcmts block">{ - paramCommentToHtml(cmtedPrs) ++ ( - mbrCmt.result match { + paramCommentToHtml(cmtedPrs, comment) ++ ( + comment.result match { case None => NodeSeq.Empty case Some(cmt) => <dt>returns</dt><dd class="cmt">{ bodyToHtml(cmt) }</dd> @@ -463,7 +463,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp } // --- start attributes block vals - val attributes: Seq[scala.xml.Node] = { + val attributes: NodeSeq = { val fvs: List[comment.Paragraph] = visibility(mbr).toList if (fvs.isEmpty || isReduced) NodeSeq.Empty else { @@ -472,7 +472,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp } } - val definitionClasses: Seq[scala.xml.Node] = { + val definitionClasses: NodeSeq = { val inDefTpls = mbr.inDefinitionTemplates if ((inDefTpls.tail.isEmpty && (inDefTpls.head == inTpl)) || isReduced) NodeSeq.Empty else { @@ -481,7 +481,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp } } - val fullSignature: Seq[scala.xml.Node] = { + val fullSignature: NodeSeq = { mbr match { case nte: NonTemplateMemberEntity if nte.isUseCase => <div class="full-signature-block toggleContainer"> @@ -492,14 +492,14 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp } } - val selfType: Seq[scala.xml.Node] = mbr match { + val selfType: NodeSeq = mbr match { case dtpl: DocTemplateEntity if (isSelf && !dtpl.selfType.isEmpty && !isReduced) => <dt>Self Type</dt> <dd>{ typeToHtml(dtpl.selfType.get, hasLinks = true) }</dd> case _ => NodeSeq.Empty } - val annotations: Seq[scala.xml.Node] = { + val annotations: NodeSeq = { // A list of annotations which don't show their arguments, e. g. because they are shown separately. val annotationsWithHiddenArguments = List("deprecated", "Deprecated", "migration") @@ -521,7 +521,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp } else NodeSeq.Empty } - val sourceLink: Seq[scala.xml.Node] = mbr match { + val sourceLink: NodeSeq = mbr match { case dtpl: DocTemplateEntity if (isSelf && dtpl.sourceUrl.isDefined && dtpl.inSource.isDefined && !isReduced) => val (absFile, _) = dtpl.inSource.get <dt>Source</dt> @@ -529,83 +529,87 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp case _ => NodeSeq.Empty } - val deprecation: Seq[scala.xml.Node] = - if (mbr.deprecation.isEmpty || isReduced) NodeSeq.Empty - else { - <dt>Deprecated</dt> - <dd class="cmt">{ bodyToHtml(mbr.deprecation.get) }</dd> + val deprecation: NodeSeq = + mbr.deprecation match { + case Some(deprecation) if !isReduced => + <dt>Deprecated</dt> + <dd class="cmt">{ bodyToHtml(deprecation) }</dd> + case _ => NodeSeq.Empty } - val migration: Seq[scala.xml.Node] = - if(mbr.migration.isEmpty || isReduced) NodeSeq.Empty - else { + val migration: NodeSeq = + mbr.migration match { + case Some(migration) if !isReduced => <dt>Migration</dt> - <dd class="cmt">{ bodyToHtml(mbr.migration.get) }</dd> + <dd class="cmt">{ bodyToHtml(migration) }</dd> + case _ => NodeSeq.Empty } - val mainComment: Seq[scala.xml.Node] = mbr.comment match { + val mainComment: NodeSeq = mbr.comment match { case Some(comment) if (! isReduced) => + def orEmpty[T](it: Iterable[T])(gen: =>NodeSeq): NodeSeq = + if (it.isEmpty) NodeSeq.Empty else gen + val example = - if(!comment.example.isEmpty) + orEmpty(comment.example) { <div class="block">Example{ if (comment.example.length > 1) "s" else ""}: - <ol>{ - val exampleXml: List[scala.xml.NodeSeq] = - for(example <- comment.example ) yield - <li class="cmt">{ bodyToHtml(example) }</li> - exampleXml.reduceLeft(_ ++ Text(", ") ++ _) + <ol>{ + val exampleXml: List[NodeSeq] = for (ex <- comment.example) yield + <li class="cmt">{ bodyToHtml(ex) }</li> + exampleXml.reduceLeft(_ ++ Text(", ") ++ _) }</ol> - </div> - else NodeSeq.Empty + </div> + } - val version: Seq[scala.xml.Node] = - if(!comment.version.isEmpty) { + val version: NodeSeq = + orEmpty(comment.version) { <dt>Version</dt> - <dd>{ for(body <- comment.version.toList) yield {bodyToHtml(body)} }</dd> - } else NodeSeq.Empty + <dd>{ for(body <- comment.version.toList) yield bodyToHtml(body) }</dd> + } - val sinceVersion: Seq[scala.xml.Node] = - if(!comment.since.isEmpty) { + val sinceVersion: NodeSeq = + orEmpty(comment.since) { <dt>Since</dt> - <dd>{ for(body <- comment.since.toList) yield {bodyToHtml(body)} }</dd> - } else NodeSeq.Empty + <dd>{ for(body <- comment.since.toList) yield bodyToHtml(body) }</dd> + } - val note: Seq[scala.xml.Node] = - if(!comment.note.isEmpty) { + val note: NodeSeq = + orEmpty(comment.note) { <dt>Note</dt> <dd>{ - val noteXml: List[scala.xml.NodeSeq] = (for(note <- comment.note ) yield <span class="cmt">{bodyToHtml(note)}</span> ) + val noteXml: List[NodeSeq] = for(note <- comment.note ) yield <span class="cmt">{bodyToHtml(note)}</span> noteXml.reduceLeft(_ ++ Text(", ") ++ _) }</dd> - } else NodeSeq.Empty + } - val seeAlso: Seq[scala.xml.Node] = - if(!comment.see.isEmpty) { + val seeAlso: NodeSeq = + orEmpty(comment.see) { <dt>See also</dt> <dd>{ - val seeXml:List[scala.xml.NodeSeq]=(for(see <- comment.see ) yield <span class="cmt">{bodyToHtml(see)}</span> ) + val seeXml: List[NodeSeq] = for(see <- comment.see ) yield <span class="cmt">{bodyToHtml(see)}</span> seeXml.reduceLeft(_ ++ _) }</dd> - } else NodeSeq.Empty + } - val exceptions: Seq[scala.xml.Node] = - if(!comment.throws.isEmpty) { + val exceptions: NodeSeq = + orEmpty(comment.throws) { <dt>Exceptions thrown</dt> <dd>{ - val exceptionsXml: Iterable[scala.xml.NodeSeq] = - for(exception <- comment.throws.toList.sortBy(_._1) ) yield - <span class="cmt">{Text(exception._1) ++ bodyToHtml(exception._2)}</span> + val exceptionsXml: List[NodeSeq] = + for((name, body) <- comment.throws.toList.sortBy(_._1) ) yield + <span class="cmt">{Text(name) ++ bodyToHtml(body)}</span> exceptionsXml.reduceLeft(_ ++ Text("") ++ _) }</dd> - } else NodeSeq.Empty + } - val todo: Seq[scala.xml.Node] = - if(!comment.todo.isEmpty) { + val todo: NodeSeq = + orEmpty(comment.todo) { <dt>To do</dt> <dd>{ - val todoXml: List[scala.xml.NodeSeq] = (for(todo <- comment.todo ) yield <span class="cmt">{bodyToHtml(todo)}</span> ) + val todoXml: List[NodeSeq] = (for(todo <- comment.todo ) yield <span class="cmt">{bodyToHtml(todo)}</span> ) todoXml.reduceLeft(_ ++ Text(", ") ++ _) }</dd> - } else NodeSeq.Empty + } example ++ version ++ sinceVersion ++ exceptions ++ todo ++ note ++ seeAlso diff --git a/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala b/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala index df7c7d3dcd..512becd04d 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala @@ -70,7 +70,7 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator { def textTypeEntity(text: String) = new TypeEntity { val name = text - def refEntity: SortedMap[Int, (LinkTo, Int)] = SortedMap() + def refEntity: SortedMap[Int, (base.LinkTo, Int)] = SortedMap() } // it seems dot chokes on node names over 8000 chars, so let's limit the size of the string diff --git a/src/compiler/scala/tools/nsc/doc/model/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/CommentFactory.scala new file mode 100644 index 0000000000..9ba89146c0 --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/model/CommentFactory.scala @@ -0,0 +1,114 @@ +/* NSC -- new Scala compiler + * Copyright 2007-2013 LAMP/EPFL + * @author Manohar Jonnalagedda + */ + +package scala.tools.nsc +package doc +package model + +import base.comment._ + +import reporters.Reporter +import scala.collection._ +import scala.reflect.internal.util.{NoPosition, Position} +import scala.language.postfixOps + +/** The comment parser transforms raw comment strings into `Comment` objects. + * Call `parse` to run the parser. Note that the parser is stateless and + * should only be built once for a given Scaladoc run. + * + * @param reporter The reporter on which user messages (error, warnings) should be printed. + * + * @author Manohar Jonnalagedda + * @author Gilles Dubochet */ +trait CommentFactory extends base.CommentFactoryBase { + thisFactory: ModelFactory with CommentFactory with MemberLookup => + + val global: Global + import global.{ reporter, definitions, Symbol } + + protected val commentCache = mutable.HashMap.empty[(Symbol, TemplateImpl), Comment] + + def addCommentBody(sym: Symbol, inTpl: TemplateImpl, docStr: String, docPos: global.Position): Symbol = { + commentCache += (sym, inTpl) -> parse(docStr, docStr, docPos, None) + sym + } + + def comment(sym: Symbol, currentTpl: Option[DocTemplateImpl], inTpl: DocTemplateImpl): Option[Comment] = { + val key = (sym, inTpl) + if (commentCache isDefinedAt key) + Some(commentCache(key)) + else { + val c = defineComment(sym, currentTpl, inTpl) + if (c isDefined) commentCache += (sym, inTpl) -> c.get + c + } + } + + /** A comment is usualy created by the parser, however for some special + * cases we have to give some `inTpl` comments (parent class for example) + * to the comment of the symbol. + * This function manages some of those cases : Param accessor and Primary constructor */ + def defineComment(sym: Symbol, currentTpl: Option[DocTemplateImpl], inTpl: DocTemplateImpl):Option[Comment] = { + + //param accessor case + // We just need the @param argument, we put it into the body + if( sym.isParamAccessor && + inTpl.comment.isDefined && + inTpl.comment.get.valueParams.isDefinedAt(sym.encodedName)) { + val comContent = Some(inTpl.comment.get.valueParams(sym.encodedName)) + Some(createComment(body0 = comContent)) + } + + // Primary constructor case + // We need some content of the class definition : @constructor for the body, + // @param and @deprecated, we can add some more if necessary + else if (sym.isPrimaryConstructor && inTpl.comment.isDefined ) { + val tplComment = inTpl.comment.get + // If there is nothing to put into the comment there is no need to create it + if(tplComment.constructor.isDefined || + tplComment.throws != Map.empty || + tplComment.valueParams != Map.empty || + tplComment.typeParams != Map.empty || + tplComment.deprecated.isDefined + ) + Some(createComment( body0 = tplComment.constructor, + throws0 = tplComment.throws, + valueParams0 = tplComment.valueParams, + typeParams0 = tplComment.typeParams, + deprecated0 = tplComment.deprecated + )) + else None + } + + //other comment cases + // parse function will make the comment + else { + val rawComment = global.expandedDocComment(sym, inTpl.sym).trim + if (rawComment != "") { + val tplOpt = if (currentTpl.isDefined) currentTpl else Some(inTpl) + val c = parse(rawComment, global.rawDocComment(sym), global.docCommentPos(sym), tplOpt) + Some(c) + } + else None + } + + } + + protected def parse(comment: String, src: String, pos: Position, inTplOpt: Option[DocTemplateImpl] = None): Comment = { + assert(!inTplOpt.isDefined || inTplOpt.get != null) + parseAtSymbol(comment, src, pos, inTplOpt map (_.sym)) + } + + /** Parses a string containing wiki syntax into a `Comment` object. + * Note that the string is assumed to be clean: + * - Removed Scaladoc start and end markers. + * - Removed start-of-line star and one whitespace afterwards (if present). + * - Removed all end-of-line whitespace. + * - Only `endOfLine` is used to mark line endings. */ + def parseWiki(string: String, pos: Position, inTplOpt: Option[DocTemplateImpl]): Body = { + assert(!inTplOpt.isDefined || inTplOpt.get != null) + parseWikiAtSymbol(string,pos, inTplOpt map (_.sym)) + } +} diff --git a/src/compiler/scala/tools/nsc/doc/model/Entity.scala b/src/compiler/scala/tools/nsc/doc/model/Entity.scala index 04046accc4..924f203a59 100644 --- a/src/compiler/scala/tools/nsc/doc/model/Entity.scala +++ b/src/compiler/scala/tools/nsc/doc/model/Entity.scala @@ -9,7 +9,7 @@ package doc package model import scala.collection._ -import comment._ +import base.comment._ import diagram._ /** An entity in a Scaladoc universe. Entities are declarations in the program and correspond to symbols in the diff --git a/src/compiler/scala/tools/nsc/doc/model/LinkTo.scala b/src/compiler/scala/tools/nsc/doc/model/LinkTo.scala deleted file mode 100644 index 361837b743..0000000000 --- a/src/compiler/scala/tools/nsc/doc/model/LinkTo.scala +++ /dev/null @@ -1,22 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2007-2013 LAMP/EPFL - */ - -package scala.tools.nsc -package doc -package model - -abstract sealed class LinkTo -final case class LinkToTpl(tpl: DocTemplateEntity) extends LinkTo -final case class LinkToMember(mbr: MemberEntity, inTpl: DocTemplateEntity) extends LinkTo -final case class Tooltip(name: String) extends LinkTo { def this(tpl: TemplateEntity) = this(tpl.qualifiedName) } -final case class LinkToExternal(name: String, url: String) extends LinkTo -case object NoLink extends LinkTo // you should use Tooltip if you have a name from the user, this is only in case all fails - -object LinkToTpl { - // this makes it easier to create links - def apply(tpl: TemplateEntity) = tpl match { - case dtpl: DocTemplateEntity => new LinkToTpl(dtpl) - case ntpl: TemplateEntity => new Tooltip(ntpl.qualifiedName) - } -} diff --git a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala index 4793716b9f..c7a767f992 100644 --- a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala +++ b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala @@ -2,225 +2,37 @@ package scala.tools.nsc package doc package model -import comment._ +import base._ /** This trait extracts all required information for documentation from compilation units */ -trait MemberLookup { +trait MemberLookup extends base.MemberLookupBase { thisFactory: ModelFactory => import global._ - import rootMirror.RootPackage, rootMirror.EmptyPackage - def makeEntityLink(title: Inline, pos: Position, query: String, inTplOpt: Option[DocTemplateImpl]) = - new EntityLink(title) { lazy val link = memberLookup(pos, query, inTplOpt) } - - def memberLookup(pos: Position, query: String, inTplOpt: Option[DocTemplateImpl]): LinkTo = { - assert(modelFinished) - - val members = breakMembers(query) - //println(query + " => " + members) - - // (1) First look in the root package, as most of the links are qualified - val fromRoot = lookupInRootPackage(pos, members) - - // (2) Or recursively go into each containing template. - val fromParents = inTplOpt.fold(Stream.empty[DocTemplateImpl]) { tpl => - Stream.iterate(tpl)(_.inTemplate) - }.takeWhile (tpl => tpl != null && !tpl.isRootPackage).map { tpl => - lookupInTemplate(pos, members, tpl.asInstanceOf[EntityImpl].sym) - } - - val syms = (fromRoot +: fromParents) find (!_.isEmpty) getOrElse Nil - val linkTo = createLinks(syms) match { - case Nil if !syms.isEmpty => - // (3) Look at external links - syms.flatMap { case (sym, owner) => - - // reconstruct the original link - def linkName(sym: Symbol) = { - def isRoot(s: Symbol) = s.isRootSymbol || s.isEmptyPackage || s.isEmptyPackageClass - def nameString(s: Symbol) = s.nameString + (if ((s.isModule || s.isModuleClass) && !s.isPackage) "$" else "") - val packageSuffix = if (sym.isPackage) ".package" else "" - - sym.ownerChain.reverse.filterNot(isRoot(_)).map(nameString(_)).mkString(".") + packageSuffix - } - - if (sym.isClass || sym.isModule || sym.isTrait || sym.isPackage) - findExternalLink(sym, linkName(sym)) - else if (owner.isClass || owner.isModule || owner.isTrait || owner.isPackage) - findExternalLink(sym, linkName(owner) + "@" + externalSignature(sym)) - else - None - } - case links => links - } - - //println(createLinks(syms)) - //println(linkTo) - - // (4) if we still haven't found anything, create a tooltip, if we found too many, report - if (linkTo.isEmpty){ - if (!settings.docNoLinkWarnings.value) - reporter.warning(pos, "Could not find any member to link for \"" + query + "\".") - Tooltip(query) - } else { - if (linkTo.length > 1) { - - val chosen = - if (linkTo.exists(_.isInstanceOf[LinkToMember])) - linkTo.collect({case lm: LinkToMember => lm}).min(Ordering[MemberEntity].on[LinkToMember](_.mbr)) - else - linkTo.head - - def linkToString(link: LinkTo) = { - val description = - link match { - case lm@LinkToMember(mbr, inTpl) => " * " + mbr.kind + " \"" + mbr.signature + "\" in " + inTpl.kind + " " + inTpl.qualifiedName - case lt@LinkToTpl(tpl) => " * " + tpl.kind + " \"" + tpl.qualifiedName + "\"" - case other => " * " + other.toString - } - val chosenInfo = - if (link == chosen) - " [chosen]" - else - "" - description + chosenInfo + "\n" + override def internalLink(sym: Symbol, site: Symbol): Option[LinkTo] = + findTemplateMaybe(sym) match { + case Some(tpl) => Some(LinkToTpl(tpl)) + case None => + findTemplateMaybe(site) flatMap { inTpl => + inTpl.members find (_.asInstanceOf[EntityImpl].sym == sym) map (LinkToMember(_, inTpl)) } - if (!settings.docNoLinkWarnings.value) - reporter.warning(pos, - "The link target \"" + query + "\" is ambiguous. Several (possibly overloaded) members fit the target:\n" + - linkTo.map(link => linkToString(link)).mkString + - (if (MemberLookup.showExplanation) - "\n\n" + - "Quick crash course on using Scaladoc links\n" + - "==========================================\n" + - "Disambiguating terms and types: Prefix terms with '$' and types with '!' in case both names are in use:\n" + - " - [[scala.collection.immutable.List!.apply class List's apply method]] and\n" + - " - [[scala.collection.immutable.List$.apply object List's apply method]]\n" + - "Disambiguating overloaded members: If a term is overloaded, you can indicate the first part of its signature followed by *:\n" + - " - [[[scala.collection.immutable.List$.fill[A](Int)(⇒A):List[A]* Fill with a single parameter]]]\n" + - " - [[[scala.collection.immutable.List$.fill[A](Int,Int)(⇒A):List[List[A]]* Fill with a two parameters]]]\n" + - "Notes: \n" + - " - you can use any number of matching square brackets to avoid interference with the signature\n" + - " - you can use \\. to escape dots in prefixes (don't forget to use * at the end to match the signature!)\n" + - " - you can use \\# to escape hashes, otherwise they will be considered as delimiters, like dots.\n" - else "") - ) - chosen - } else - linkTo.head - } - } - - private abstract class SearchStrategy - private object BothTypeAndTerm extends SearchStrategy - private object OnlyType extends SearchStrategy - private object OnlyTerm extends SearchStrategy - - private def lookupInRootPackage(pos: Position, members: List[String]) = - lookupInTemplate(pos, members, EmptyPackage) ::: lookupInTemplate(pos, members, RootPackage) - - private def createLinks(syms: List[(Symbol, Symbol)]): List[LinkTo] = - syms.flatMap { case (sym, owner) => - findTemplateMaybe(sym) match { - case Some(tpl) => LinkToTpl(tpl) :: Nil - case None => - findTemplateMaybe(owner) flatMap { inTpl => - inTpl.members find (_.asInstanceOf[EntityImpl].sym == sym) map (LinkToMember(_, inTpl)) - } - } } - private def lookupInTemplate(pos: Position, members: List[String], container: Symbol): List[(Symbol, Symbol)] = { - // Maintaining compatibility with previous links is a bit tricky here: - // we have a preference for term names for all terms except for the last, where we prefer a class: - // How to do this: - // - at each step we do a DFS search with the prefered strategy - // - if the search doesn't return any members, we backtrack on the last decision - // * we look for terms with the last member's name - // * we look for types with the same name, all the way up - val result = members match { - case Nil => Nil - case mbrName::Nil => - var syms = lookupInTemplate(pos, mbrName, container, OnlyType) map ((_, container)) - if (syms.isEmpty) - syms = lookupInTemplate(pos, mbrName, container, OnlyTerm) map ((_, container)) - syms - - case tplName::rest => - def completeSearch(syms: List[Symbol]) = - syms flatMap (lookupInTemplate(pos, rest, _)) - - completeSearch(lookupInTemplate(pos, tplName, container, OnlyTerm)) match { - case Nil => completeSearch(lookupInTemplate(pos, tplName, container, OnlyType)) - case syms => syms - } + override def chooseLink(links: List[LinkTo]): LinkTo = { + val mbrs = links.collect { + case lm@LinkToMember(mbr: MemberEntity, _) => (mbr, lm) } - //println("lookupInTemplate(" + members + ", " + container + ") => " + result) - result - } - - private def lookupInTemplate(pos: Position, member: String, container: Symbol, strategy: SearchStrategy): List[Symbol] = { - val name = member.stripSuffix("$").stripSuffix("!").stripSuffix("*") - def signatureMatch(sym: Symbol): Boolean = externalSignature(sym).startsWith(name) - - // We need to cleanup the bogus classes created by the .class file parser. For example, [[scala.Predef]] resolves - // to (bogus) class scala.Predef loaded by the class loader -- which we need to eliminate by looking at the info - // and removing NoType classes - def cleanupBogusClasses(syms: List[Symbol]) = { syms.filter(_.info != NoType) } - - def syms(name: Name) = container.info.nonPrivateMember(name.encodedName).alternatives - def termSyms = cleanupBogusClasses(syms(newTermName(name))) - def typeSyms = cleanupBogusClasses(syms(newTypeName(name))) - - val result = if (member.endsWith("$")) - termSyms - else if (member.endsWith("!")) - typeSyms - else if (member.endsWith("*")) - cleanupBogusClasses(container.info.nonPrivateDecls) filter signatureMatch + if (mbrs.isEmpty) + links.head else - if (strategy == BothTypeAndTerm) - termSyms ::: typeSyms - else if (strategy == OnlyType) - typeSyms - else if (strategy == OnlyTerm) - termSyms - else - Nil - - //println("lookupInTemplate(" + member + ", " + container + ") => " + result) - result + mbrs.min(Ordering[MemberEntity].on[(MemberEntity, LinkTo)](_._1))._2 } - private def breakMembers(query: String): List[String] = { - // Okay, how does this work? Well: you split on . but you don't want to split on \. => thus the ugly regex - // query.split((?<=[^\\\\])\\.).map(_.replaceAll("\\.")) - // The same code, just faster: - var members = List[String]() - var index = 0 - var last_index = 0 - val length = query.length - while (index < length) { - if ((query.charAt(index) == '.' || query.charAt(index) == '#') && - ((index == 0) || (query.charAt(index-1) != '\\'))) { - - val member = query.substring(last_index, index).replaceAll("\\\\([#\\.])", "$1") - // we want to allow javadoc-style links [[#member]] -- which requires us to remove empty members from the first - // elemnt in the list - if ((member != "") || (!members.isEmpty)) - members ::= member - last_index = index + 1 - } - index += 1 - } - if (last_index < length) - members ::= query.substring(last_index, length).replaceAll("\\\\\\.", ".") - members.reverse + override def toString(link: LinkTo) = link match { + case LinkToTpl(tpl: EntityImpl) => tpl.sym.toString + case LinkToMember(mbr: EntityImpl, inTpl: EntityImpl) => + mbr.sym.signatureString + " in " + inTpl.sym.toString + case _ => link.toString } } - -object MemberLookup { - private[this] var _showExplanation = true - def showExplanation: Boolean = if (_showExplanation) { _showExplanation = false; true } else false -} diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 4dac5b7d90..dc75b15f87 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -4,8 +4,8 @@ package scala.tools.nsc package doc package model -import comment._ - +import base._ +import base.comment._ import diagram._ import scala.collection._ @@ -1038,32 +1038,5 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { (bSym.isAliasType || bSym.isAbstractType) && { val rawComment = global.expandedDocComment(bSym, inTpl.sym) rawComment.contains("@template") || rawComment.contains("@documentable") } - - def findExternalLink(sym: Symbol, name: String): Option[LinkTo] = { - val sym1 = - if (sym == AnyClass || sym == AnyRefClass || sym == AnyValClass || sym == NothingClass) ListClass - else if (sym.isPackage) - /* Get package object which has associatedFile ne null */ - sym.info.member(newTermName("package")) - else sym - Option(sym1.associatedFile) flatMap (_.underlyingSource) flatMap { src => - val path = src.path - settings.extUrlMapping get path map { url => - LinkToExternal(name, url + "#" + name) - } - } orElse { - // Deprecated option. - settings.extUrlPackageMapping find { - case (pkg, _) => name startsWith pkg - } map { - case (_, url) => LinkToExternal(name, url + "#" + name) - } - } - } - - def externalSignature(sym: Symbol) = { - sym.info // force it, otherwise we see lazy types - (sym.nameString + sym.signatureString).replaceAll("\\s", "") - } } diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala index 015fce294e..5d2cc51c97 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala @@ -10,8 +10,6 @@ package scala.tools.nsc package doc package model -import comment._ - import scala.collection._ import symtab.Flags diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala index 1876415f2a..99e9059d79 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala @@ -4,8 +4,7 @@ package scala.tools.nsc package doc package model -import comment._ - +import base._ import diagram._ import scala.collection._ @@ -17,7 +16,8 @@ trait ModelFactoryTypeSupport { with ModelFactoryTypeSupport with DiagramFactory with CommentFactory - with TreeFactory => + with TreeFactory + with MemberLookup => import global._ import definitions.{ ObjectClass, NothingClass, AnyClass, AnyValClass, AnyRefClass } @@ -82,7 +82,10 @@ trait ModelFactoryTypeSupport { findTemplateMaybe(bSym) match { case Some(bTpl) if owner == bSym.owner => // (0) the owner's class is linked AND has a template - lovely - LinkToTpl(bTpl) + bTpl match { + case dtpl: DocTemplateEntity => new LinkToTpl(dtpl) + case _ => new Tooltip(bTpl.qualifiedName) + } case _ => val oTpl = findTemplateMaybe(owner) (oTpl, oTpl flatMap (findMember(bSym, _))) match { diff --git a/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala b/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala index e4a053e115..cf5c1fb3fb 100644 --- a/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala +++ b/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala @@ -20,7 +20,7 @@ abstract class TypeEntity { /** Maps which parts of this type's name reference entities. The map is indexed by the position of the first * character that reference some entity, and contains the entity and the position of the last referenced * character. The referenced character ranges do not to overlap or nest. The map is sorted by position. */ - def refEntity: SortedMap[Int, (LinkTo, Int)] + def refEntity: SortedMap[Int, (base.LinkTo, Int)] /** The human-readable representation of this type. */ override def toString = name diff --git a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala index fbf6e3386b..96bba0498c 100644 --- a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala +++ b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala @@ -3,7 +3,6 @@ package model package diagram import model._ -import comment.CommentFactory import java.util.regex.{Pattern, Matcher} import scala.util.matching.Regex diff --git a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala index 849a2ac4b3..ebac25bbe4 100644 --- a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala @@ -3,7 +3,6 @@ package model package diagram import model._ -import comment.CommentFactory // statistics import html.page.diagram.DiagramStats @@ -24,7 +23,7 @@ trait DiagramFactory extends DiagramDirectiveParser { // the following can used for hardcoding different relations into the diagram, for bootstrapping purposes def aggregationNode(text: String) = - NormalNode(new TypeEntity { val name = text; val refEntity = SortedMap[Int, (LinkTo, Int)]() }, None)() + NormalNode(new TypeEntity { val name = text; val refEntity = SortedMap[Int, (base.LinkTo, Int)]() }, None)() /** Create the inheritance diagram for this template */ def makeInheritanceDiagram(tpl: DocTemplateImpl): Option[Diagram] = { diff --git a/src/compiler/scala/tools/nsc/interactive/Doc.scala b/src/compiler/scala/tools/nsc/interactive/Doc.scala new file mode 100755 index 0000000000..ad28a28105 --- /dev/null +++ b/src/compiler/scala/tools/nsc/interactive/Doc.scala @@ -0,0 +1,59 @@ +/* NSC -- new Scala compiler + * Copyright 2007-2012 LAMP/EPFL + * @author Eugene Vigdorchik + */ + +package scala.tools.nsc +package interactive + +import doc.base._ +import comment._ +import scala.xml.NodeSeq + +sealed trait DocResult +final case class UrlResult(url: String) extends DocResult +final case class HtmlResult(comment: Comment) extends DocResult + +abstract class Doc(val settings: doc.Settings) extends MemberLookupBase with CommentFactoryBase { + + override val global: interactive.Global + import global._ + + def chooseLink(links: List[LinkTo]): LinkTo + + override def internalLink(sym: Symbol, site: Symbol): Option[LinkTo] = + ask { () => + if (sym.isClass || sym.isModule) + Some(LinkToTpl(sym)) + else + if ((site.isClass || site.isModule) && site.info.members.toList.contains(sym)) + Some(LinkToMember(sym, site)) + else + None + } + + override def toString(link: LinkTo) = ask { () => + link match { + case LinkToMember(mbr: Symbol, site: Symbol) => + mbr.signatureString + " in " + site.toString + case LinkToTpl(sym: Symbol) => sym.toString + case _ => link.toString + } + } + + def retrieve(sym: Symbol, site: Symbol): Option[DocResult] = { + val sig = ask { () => externalSignature(sym) } + findExternalLink(sym, sig) map { link => UrlResult(link.url) } orElse { + val resp = new Response[Tree] + // Ensure docComment tree is type-checked. + val pos = ask { () => docCommentPos(sym) } + askTypeAt(pos, resp) + resp.get.left.toOption flatMap { _ => + ask { () => + val comment = parseAtSymbol(expandedDocComment(sym), rawDocComment(sym), pos, Some(site)) + Some(HtmlResult(comment)) + } + } + } + } +} diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 9716c75215..07ffe9e437 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -52,7 +52,6 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") import log.logreplay debugLog("logger: " + log.getClass + " writing to " + (new java.io.File(logName)).getAbsolutePath) debugLog("classpath: "+classPath) - Console.err.println("\n ======= CHECK THREAD ACCESS compiler build ========\n") private var curTime = System.nanoTime private def timeStep = { @@ -70,6 +69,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") if (verboseIDE) println("[%s][%s]".format(projectName, msg)) override def forInteractive = true + override def forScaladoc = settings.isScaladoc /** A map of all loaded files to the rich compilation units that correspond to them. */ diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala index b3f80168ff..11ae7c974b 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala @@ -7,6 +7,7 @@ import reporters.{Reporter => CompilerReporter} /** Trait encapsulating the creation of a presentation compiler's instance.*/ private[tests] trait PresentationCompilerInstance extends TestSettings { protected val settings = new Settings + protected def docSettings: doc.Settings = new doc.Settings(_ => ()) protected val compilerReporter: CompilerReporter = new InteractiveReporter { override def compiler = PresentationCompilerInstance.this.compiler } diff --git a/src/compiler/scala/tools/nsc/io/Jar.scala b/src/compiler/scala/tools/nsc/io/Jar.scala index 49a1ff114f..0dca75dab9 100644 --- a/src/compiler/scala/tools/nsc/io/Jar.scala +++ b/src/compiler/scala/tools/nsc/io/Jar.scala @@ -47,6 +47,20 @@ class Jar(file: File) extends Iterable[JarEntry] { case _ => Nil } + /** Invoke f with input for named jar entry (or None). */ + def withEntryStream[A](name: String)(f: Option[InputStream] => A) = { + val jarFile = new JarFile(file.jfile) + def apply() = + jarFile getEntry name match { + case null => f(None) + case entry => + val in = Some(jarFile getInputStream entry) + try f(in) + finally in map (_.close()) + } + try apply() finally jarFile.close() + } + def withJarInput[T](f: JarInputStream => T): T = { val in = new JarInputStream(file.inputStream()) try f(in) diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala index 093f8285e1..b0113f7696 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala @@ -6,10 +6,14 @@ package scala.tools.nsc package plugins -import io.{ Path, Jar } -import java.net.URLClassLoader -import java.util.jar.JarFile +import scala.tools.nsc.io.{ Jar } +import scala.tools.nsc.util.ScalaClassLoader +import scala.reflect.io.{ Directory, File, Path } +import java.io.InputStream import java.util.zip.ZipException + +import scala.collection.mutable.ListBuffer +import scala.util.{ Try, Success, Failure } import scala.xml.XML /** Information about a plugin loaded from a jar file. @@ -34,11 +38,13 @@ abstract class Plugin { val description: String /** The compiler that this plugin uses. This is normally equated - * to a constructor parameter in the concrete subclass. */ + * to a constructor parameter in the concrete subclass. + */ val global: Global /** Handle any plugin-specific options. The `-P:plugname:` part - * will not be present. */ + * will not be present. + */ def processOptions(options: List[String], error: String => Unit) { if (!options.isEmpty) error("Error: " + name + " has no options") @@ -60,90 +66,86 @@ object Plugin { private val PluginXML = "scalac-plugin.xml" - /** Create a class loader with the specified file plus + /** Create a class loader with the specified locations plus * the loader that loaded the Scala compiler. */ - private def loaderFor(jarfiles: Seq[Path]): ClassLoader = { + private def loaderFor(locations: Seq[Path]): ScalaClassLoader = { val compilerLoader = classOf[Plugin].getClassLoader - val jarurls = jarfiles map (_.toURL) + val urls = locations map (_.toURL) - new URLClassLoader(jarurls.toArray, compilerLoader) + ScalaClassLoader fromURLs (urls, compilerLoader) } - /** Try to load a plugin description from the specified - * file, returning `None` if it does not work. + /** Try to load a plugin description from the specified location. */ - private def loadDescription(jarfile: Path): Option[PluginDescription] = - // XXX Return to this once we have some ARM support - if (!jarfile.exists) None - else try { - val jar = new JarFile(jarfile.jfile) - - try { - jar getEntry PluginXML match { - case null => None - case entry => - val in = jar getInputStream entry - val packXML = XML load in - in.close() - - PluginDescription fromXML packXML - } - } - finally jar.close() - } - catch { - case _: ZipException => None + private def loadDescriptionFromJar(jarp: Path): Try[PluginDescription] = { + // XXX Return to this once we have more ARM support + def read(is: Option[InputStream]) = is match { + case None => throw new RuntimeException(s"Missing $PluginXML in $jarp") + case _ => PluginDescription fromXML (XML load is.get) } + Try(new Jar(jarp.jfile).withEntryStream(PluginXML)(read)) + } + + private def loadDescriptionFromFile(f: Path): Try[PluginDescription] = + Try(XML loadFile f.jfile) map (PluginDescription fromXML _) type AnyClass = Class[_] - /** Loads a plugin class from the named jar file. + /** Use a class loader to load the plugin class. * - * @return `None` if the jar file has no plugin in it or - * if the plugin is badly formed. + * @return `None` on failure */ - def loadFrom(jarfile: Path, loader: ClassLoader): Option[AnyClass] = - loadDescription(jarfile) match { - case None => - println("Warning: could not load descriptor for plugin %s".format(jarfile)) - None - case Some(pdesc) => - try Some(loader loadClass pdesc.classname) catch { - case _: Exception => - println("Warning: class not found for plugin in %s (%s)".format(jarfile, pdesc.classname)) - None - } + def load(pd: PluginDescription, loader: ClassLoader): Try[AnyClass] = { + Try[AnyClass] { + loader loadClass pd.classname + } recoverWith { + case _: Exception => + Failure(new RuntimeException(s"Warning: class not found: ${pd.classname}")) } + } - /** Load all plugins found in the argument list, both in the - * jar files explicitly listed, and in the jar files in the - * directories specified. Skips all plugins in `ignoring`. + /** Load all plugins specified by the arguments. + * Each of `jars` must be a valid plugin archive or exploded archive. + * Each of `dirs` may be a directory containing arbitrary plugin archives. + * Skips all plugins named in `ignoring`. * A single classloader is created and used to load all of them. */ def loadAllFrom( jars: List[Path], dirs: List[Path], - ignoring: List[String]): List[AnyClass] = + ignoring: List[String]): List[Try[AnyClass]] = { - val alljars = (jars ::: (for { - dir <- dirs if dir.isDirectory - entry <- dir.toDirectory.files.toList sortBy (_.name) -// was: if Path.isJarOrZip(entry) - if Jar.isJarOrZip(entry) - pdesc <- loadDescription(entry) - if !(ignoring contains pdesc.name) - } yield entry)).distinct - - val loader = loaderFor(alljars) - (alljars map (loadFrom(_, loader))).flatten + // List[(jar, Success(descriptor))] in dir + def scan(d: Directory) = for { + f <- d.files.toList sortBy (_.name) + if Jar isJarOrZip f + pd = loadDescriptionFromJar(f) + if pd.isSuccess + } yield (f, pd) + // (dir, Try(descriptor)) + def explode(d: Directory) = d -> loadDescriptionFromFile(d / PluginXML) + // (j, Try(descriptor)) + def required(j: Path) = j -> loadDescriptionFromJar(j) + + type Paired = Pair[Path, Try[PluginDescription]] + val included: List[Paired] = (dirs flatMap (_ ifDirectory scan)).flatten + val exploded: List[Paired] = jars flatMap (_ ifDirectory explode) + val explicit: List[Paired] = jars flatMap (_ ifFile required) + def ignored(p: Paired) = p match { + case (path, Success(pd)) => ignoring contains pd.name + case _ => false + } + val (locs, pds) = ((explicit ::: exploded ::: included) filterNot ignored).unzip + + val loader = loaderFor(locs.distinct) + pds filter (_.isSuccess) map (_.get) map (Plugin load (_, loader)) } /** Instantiate a plugin class, given the class and * the compiler it is to be used in. */ def instantiate(clazz: AnyClass, global: Global): Plugin = { - val constructor = clazz getConstructor classOf[Global] - (constructor newInstance global).asInstanceOf[Plugin] + (clazz getConstructor classOf[Global] newInstance global).asInstanceOf[Plugin] } } diff --git a/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala b/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala index 4d98b2563c..c6e1af7ea4 100644 --- a/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala +++ b/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala @@ -18,8 +18,12 @@ abstract class PluginComponent extends SubComponent { /** Internal flag to tell external from internal phases */ final override val internal = false - /** Phases supplied by plugins should not have give the runsRightAfter constraint, - * but can override it */ + /** Phases supplied by plugins should not have to supply the + * runsRightAfter constraint, but can override it. + */ val runsRightAfter: Option[String] = None + /** Useful for -Xshow-phases. */ + def description: String = "" + } diff --git a/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala b/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala index f77123ba11..27693d1a45 100644 --- a/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala +++ b/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala @@ -13,17 +13,12 @@ import scala.xml.Node * * @author Lex Spoon * @version 1.0, 2007-5-21 + * @param name A short name of the plugin, used to identify it in + * various contexts. The phase defined by the plugin + * should have the same name. + * @param classname The name of the main Plugin class. */ -abstract class PluginDescription { - - /** A short name of the compiler, used to identify it in - * various contexts. The phase defined by the plugin - * should have the same name. - */ - val name: String - - /** The name of the main class for the plugin */ - val classname: String +case class PluginDescription(name: String, classname: String) { /** An XML representation of this description. It can be * read back using `PluginDescription.fromXML`. @@ -44,32 +39,24 @@ abstract class PluginDescription { */ object PluginDescription { - def fromXML(xml: Node): Option[PluginDescription] = { - // check the top-level tag - xml match { - case <plugin>{_*}</plugin> => () - case _ => return None - } + def fromXML(xml: Node): PluginDescription = { // extract one field def getField(field: String): Option[String] = { val text = (xml \\ field).text.trim if (text == "") None else Some(text) } - - // extract the required fields - val name1 = getField("name") match { - case None => return None - case Some(str) => str + def extracted = { + val name = "name" + val claas = "classname" + val vs = Map(name -> getField(name), claas -> getField(claas)) + if (vs.values exists (_.isEmpty)) fail() + else PluginDescription(name = vs(name).get, classname = vs(claas).get) } - val classname1 = getField("classname") match { - case None => return None - case Some(str) => str + def fail() = throw new RuntimeException("Bad plugin descriptor.") + // check the top-level tag + xml match { + case <plugin>{_*}</plugin> => extracted + case _ => fail() } - - Some(new PluginDescription { - val name = name1 - val classname = classname1 - }) } - } diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala index 736bd826e4..bb7d54d8f6 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala @@ -7,7 +7,8 @@ package scala.tools.nsc package plugins -import io.{ File, Path } +import scala.reflect.io.{ File, Path } +import scala.tools.util.PathResolver.Defaults /** Support for run-time loading of compiler plugins. * @@ -25,8 +26,14 @@ trait Plugins { */ protected def loadRoughPluginsList(): List[Plugin] = { val jars = settings.plugin.value map Path.apply - val dirs = (settings.pluginsDir.value split File.pathSeparator).toList map Path.apply - val classes = Plugin.loadAllFrom(jars, dirs, settings.disable.value) + def injectDefault(s: String) = if (s.isEmpty) Defaults.scalaPluginPath else s + val dirs = (settings.pluginsDir.value split File.pathSeparator).toList map injectDefault map Path.apply + val maybes = Plugin.loadAllFrom(jars, dirs, settings.disable.value) + val (goods, errors) = maybes partition (_.isSuccess) + errors foreach (_ recover { + case e: Exception => inform(e.getMessage) + }) + val classes = goods map (_.get) // flatten // Each plugin must only be instantiated once. A common pattern // is to register annotation checkers during object construction, so @@ -106,7 +113,7 @@ trait Plugins { * @see phasesSet */ protected def computePluginPhases(): Unit = - phasesSet ++= (plugins flatMap (_.components)) + for (p <- plugins; c <- p.components) addToPhasesSet(c, c.description) /** Summary of the options for all loaded plugins */ def pluginOptionsHelp: String = diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index caa45ea6db..efe7519d5e 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -148,9 +148,34 @@ abstract class Pickler extends SubComponent { true } + /** If the symbol is a type skolem, deskolemize and log it. + * If we fail to deskolemize, in a method like + * trait Trait[+A] { def f[CC[X]] : CC[A] } + * the applied type CC[A] will hold a different CC symbol + * than the type-constructor type-parameter CC. + */ + private def deskolemize(sym: Symbol) = { + if (sym.isTypeSkolem) { + val sym1 = sym.deSkolemize + log({ + val what0 = sym.defString + val what = sym1.defString match { + case `what0` => what0 + case other => what0 + "->" + other + } + val where = sym.enclMethod.fullLocationString + s"deskolemizing $what in $where" + }) + sym1 + } + else sym + } + /** Store symbol in index. If symbol is local, also store everything it references. */ - def putSymbol(sym: Symbol) { + def putSymbol(sym0: Symbol) { + val sym = deskolemize(sym0) + if (putEntry(sym)) { if (isLocal(sym)) { putEntry(sym.name) @@ -503,7 +528,13 @@ abstract class Pickler extends SubComponent { /** Write a reference to object, i.e., the object's number in the map index. */ - private def writeRef(ref: AnyRef) { writeNat(index(ref)) } + private def writeRef(ref0: AnyRef) { + val ref = ref0 match { + case sym: Symbol => deskolemize(sym) + case _ => ref0 + } + writeNat(index(ref)) + } private def writeRefs(refs: List[AnyRef]) { refs foreach writeRef } private def writeRefsWithLength(refs: List[AnyRef]) { writeNat(refs.length) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 45bd5cf003..13d3bb23cb 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -857,8 +857,7 @@ abstract class Erasure extends AddInterfaces alt => alt == first || !(first.tpe looselyMatches alt.tpe) } if (tree.symbol ne sym1) { - tree1.symbol = sym1 - tree1.tpe = sym1.tpe + tree1 setSymbol sym1 setType sym1.tpe } } tree1 @@ -1260,13 +1259,12 @@ abstract class Erasure extends AddInterfaces tree1 setType specialScalaErasure(tree1.tpe) case ArrayValue(elemtpt, trees) => treeCopy.ArrayValue( - tree1, elemtpt setType specialScalaErasure.applyInArray(elemtpt.tpe), trees map transform) setType null + tree1, elemtpt setType specialScalaErasure.applyInArray(elemtpt.tpe), trees map transform).clearType() case DefDef(_, _, _, _, tpt, _) => - val result = super.transform(tree1) setType null - tpt.tpe = specialErasure(tree1.symbol)(tree1.symbol.tpe).resultType - result + try super.transform(tree1).clearType() + finally tpt setType specialErasure(tree1.symbol)(tree1.symbol.tpe).resultType case _ => - super.transform(tree1) setType null + super.transform(tree1).clearType() } } } diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 45ef083b66..0769b67282 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -396,8 +396,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { } sourceModule setInfo sym.tpe // Companion module isn't visible for anonymous class at this point anyway - assert(clazz.sourceModule != NoSymbol || clazz.isAnonymousClass, - clazz + " has no sourceModule: sym = " + sym + " sym.tpe = " + sym.tpe) + assert(clazz.sourceModule != NoSymbol || clazz.isAnonymousClass, s"$clazz has no sourceModule: $sym ${sym.tpe}") parents1 = List() decls1 = newScopeWith(decls.toList filter isImplementedStatically: _*) } else if (!parents.isEmpty) { @@ -545,12 +544,18 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { } tree } + // !!! What is this doing, and why is it only looking for exactly + // one type parameter? It would seem to be + // "Map implementation class types in type-apply's to their interfaces" + // from the comment on preTransform, but is there some way we should know + // that impl class types in type applies can only appear in single + // type parameter type constructors? case Apply(tapp @ TypeApply(fn, List(arg)), List()) => if (arg.tpe.typeSymbol.isImplClass) { val ifacetpe = toInterface(arg.tpe) - arg.tpe = ifacetpe - tapp.tpe = MethodType(List(), ifacetpe) - tree.tpe = ifacetpe + arg setType ifacetpe + tapp setType MethodType(Nil, ifacetpe) + tree setType ifacetpe } tree case ValDef(_, _, _, _) if currentOwner.isImplClass => @@ -1129,7 +1134,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { // change every node type that refers to an implementation class to its // corresponding interface, unless the node's symbol is an implementation class. if (tree.tpe.typeSymbol.isImplClass && ((sym eq null) || !sym.isImplClass)) - tree.tpe = toInterface(tree.tpe) + tree modifyType toInterface tree match { case templ @ Template(parents, self, body) => diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index e3239313de..173ca1e628 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -998,6 +998,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case (overridden, env) => val om = specializedOverload(clazz, overridden, env) clazz.info.decls.enter(om) + foreachWithIndex(om.paramss) { (params, i) => + foreachWithIndex(params) { (param, j) => + param.name = overriding.paramss(i)(j).name // SI-6555 Retain the parameter names from the subclass. + } + } debuglog("specialized overload %s for %s in %s: %s".format(om, overriding.name.decode, pp(env), om.info)) if (overriding.isAbstractOverride) om.setFlag(ABSOVERRIDE) typeEnv(om) = env @@ -1245,9 +1250,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { class BodyDuplicator(_context: Context) extends super.BodyDuplicator(_context) { override def castType(tree: Tree, pt: Type): Tree = { - // log(" expected type: " + pt) - // log(" tree type: " + tree.tpe) - tree.tpe = if (tree.tpe != null) fixType(tree.tpe) else null + tree modifyType fixType // log(" tree type: " + tree.tpe) val ntree = if (tree.tpe != null && !(tree.tpe <:< pt)) { val casttpe = CastMap(tree.tpe) @@ -1255,8 +1258,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { else if (casttpe <:< CastMap(pt)) gen.mkCast(tree, pt) else tree } else tree - ntree.tpe = null - ntree + + ntree.clearType() } } @@ -1684,8 +1687,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { false) // don't make private fields public val newBody = symSubstituter(body(source).duplicate) - tpt.tpe = tpt.tpe.substSym(oldtparams, newtparams) - + tpt modifyType (_.substSym(oldtparams, newtparams)) copyDefDef(tree)(vparamss = List(newSyms map ValDef), rhs = newBody) } diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 90ea6c94d8..b94ae99263 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -234,7 +234,10 @@ abstract class UnCurry extends InfoTransform val applyMethodDef = { val methSym = anonClass.newMethod(nme.apply, fun.pos, FINAL) - methSym setInfoAndEnter MethodType(methSym newSyntheticValueParams formals, restpe) + val paramSyms = map2(formals, fun.vparams) { + (tp, param) => methSym.newSyntheticValueParam(tp, param.name) + } + methSym setInfoAndEnter MethodType(paramSyms, restpe) fun.vparams foreach (_.symbol.owner = methSym) fun.body changeOwner (fun.symbol -> methSym) diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 30c12a4286..27944b8767 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -154,7 +154,7 @@ trait ContextErrors { // the found/req types. val foundType: Type = req.normalize match { case RefinedType(parents, decls) if !decls.isEmpty && found.typeSymbol.isAnonOrRefinementClass => - val retyped = typed (tree.duplicate setType null) + val retyped = typed (tree.duplicate.clearType()) val foundDecls = retyped.tpe.decls filter (sym => !sym.isConstructor && !sym.isSynthetic) if (foundDecls.isEmpty || (found.typeSymbol eq NoSymbol)) found else { @@ -182,7 +182,7 @@ trait ContextErrors { } def ParentTypesError(templ: Template, ex: TypeError) = { - templ.tpe = null + templ.clearType() issueNormalTypeError(templ, ex.getMessage()) setError(templ) } @@ -977,7 +977,7 @@ trait ContextErrors { object SymValidateErrors extends Enumeration { val ImplicitConstr, ImplicitNotTermOrClass, ImplicitAtToplevel, OverrideClass, SealedNonClass, AbstractNonClass, - OverrideConstr, AbstractOverride, LazyAndEarlyInit, + OverrideConstr, AbstractOverride, AbstractOverrideOnTypeMember, LazyAndEarlyInit, ByNameParameter, AbstractVar = Value } @@ -1076,6 +1076,9 @@ trait ContextErrors { case AbstractOverride => "`abstract override' modifier only allowed for members of traits" + case AbstractOverrideOnTypeMember => + "`abstract override' modifier not allowed for type members" + case LazyAndEarlyInit => "`lazy' definitions may not be initialized early" diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index c0d2f44c7b..e8c48184b0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -106,8 +106,8 @@ trait Contexts { self: Analyzer => var sc = startContext while (sc != NoContext) { sc.tree match { - case Import(qual, _) => qual.tpe = singleType(qual.symbol.owner.thisType, qual.symbol) - case _ => + case Import(qual, _) => qual setType singleType(qual.symbol.owner.thisType, qual.symbol) + case _ => } sc = sc.outer } @@ -436,16 +436,7 @@ trait Contexts { self: Analyzer => case _ => outer.isLocal() } - /** Fast path for some slow checks (ambiguous assignment in Refchecks, and - * existence of __match for MatchTranslation in virtpatmat.) This logic probably - * needs improvement. - */ - def isNameInScope(name: Name) = ( - enclosingContextChain exists (ctx => - (ctx.scope.lookupEntry(name) != null) - || (ctx.owner.rawInfo.member(name) != NoSymbol) - ) - ) + def isNameInScope(name: Name) = lookupSymbol(name, _ => true).isSuccess // nextOuter determines which context is searched next for implicits // (after `this`, which contributes `newImplicits` below.) In diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index 9c23b8663c..1c48eeed70 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -210,40 +210,35 @@ abstract class Duplicators extends Analyzer { tree match { case ttree @ TypeTree() => // log("fixing tpe: " + tree.tpe + " with sym: " + tree.tpe.typeSymbol) - ttree.tpe = fixType(ttree.tpe) - ttree + ttree modifyType fixType case Block(stats, res) => debuglog("invalidating block") invalidateAll(stats) invalidate(res) - tree.tpe = null - super.typed(tree, mode, pt) + super.typed(tree.clearType(), mode, pt) case ClassDef(_, _, _, tmpl @ Template(parents, _, stats)) => // log("invalidating classdef " + tree) tmpl.symbol = tree.symbol.newLocalDummy(tree.pos) invalidateAll(stats, tree.symbol) - tree.tpe = null - super.typed(tree, mode, pt) + super.typed(tree.clearType(), mode, pt) case ddef @ DefDef(_, _, _, _, tpt, rhs) => - ddef.tpt.tpe = fixType(ddef.tpt.tpe) - ddef.tpe = null - super.typed(ddef, mode, pt) + ddef.tpt modifyType fixType + super.typed(ddef.clearType(), mode, pt) case vdef @ ValDef(mods, name, tpt, rhs) => // log("vdef fixing tpe: " + tree.tpe + " with sym: " + tree.tpe.typeSymbol + " and " + invalidSyms) //if (mods.hasFlag(Flags.LAZY)) vdef.symbol.resetFlag(Flags.MUTABLE) // Martin to Iulian: lazy vars can now appear because they are no longer boxed; Please check that deleting this statement is OK. - vdef.tpt.tpe = fixType(vdef.tpt.tpe) - vdef.tpe = null - super.typed(vdef, mode, pt) + vdef.tpt modifyType fixType + super.typed(vdef.clearType(), mode, pt) case ldef @ LabelDef(name, params, rhs) => // log("label def: " + ldef) // in case the rhs contains any definitions -- TODO: is this necessary? invalidate(rhs) - ldef.tpe = null + ldef.clearType() // is this LabelDef generated by tailcalls? val isTailLabel = (ldef.params.length >= 1) && (ldef.params.head.name == nme.THIS) @@ -261,27 +256,23 @@ abstract class Duplicators extends Analyzer { val params1 = params map newParam val rhs1 = (new TreeSubstituter(params map (_.symbol), params1) transform rhs) // TODO: duplicate? - rhs1.tpe = null - super.typed(treeCopy.LabelDef(tree, name, params1, rhs1), mode, pt) + super.typed(treeCopy.LabelDef(tree, name, params1, rhs1.clearType()), mode, pt) case Bind(name, _) => // log("bind: " + tree) invalidate(tree) - tree.tpe = null - super.typed(tree, mode, pt) + super.typed(tree.clearType(), mode, pt) case Ident(_) if tree.symbol.isLabel => debuglog("Ident to labeldef " + tree + " switched to ") tree.symbol = updateSym(tree.symbol) - tree.tpe = null - super.typed(tree, mode, pt) + super.typed(tree.clearType(), mode, pt) case Ident(_) if (origtreesym ne null) && origtreesym.isLazy => debuglog("Ident to a lazy val " + tree + ", " + tree.symbol + " updated to " + origtreesym) tree.symbol = updateSym(origtreesym) - tree.tpe = null - super.typed(tree, mode, pt) + super.typed(tree.clearType(), mode, pt) case Select(th @ This(_), sel) if (oldClassOwner ne null) && (th.symbol == oldClassOwner) => // We use the symbol name instead of the tree name because the symbol diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala index 2806d7b2d9..4fbb788c7b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala +++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala @@ -94,11 +94,11 @@ trait EtaExpansion { self: Analyzer => // with repeated params, there might be more or fewer args than params liftout(arg, byName(i).getOrElse(false)) } - treeCopy.Apply(tree, liftoutPrefix(fn), newArgs) setType null + treeCopy.Apply(tree, liftoutPrefix(fn), newArgs).clearType() case TypeApply(fn, args) => - treeCopy.TypeApply(tree, liftoutPrefix(fn), args) setType null + treeCopy.TypeApply(tree, liftoutPrefix(fn), args).clearType() case Select(qual, name) => - treeCopy.Select(tree, liftout(qual, false), name) setSymbol NoSymbol setType null + treeCopy.Select(tree, liftout(qual, false), name).clearType() setSymbol NoSymbol case Ident(name) => tree } diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index bf5aa95f22..8d869b669c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -938,8 +938,8 @@ trait Implicits { * - for alias types and abstract types, we take instead the parts * - of their upper bounds. * @return For those parts that refer to classes with companion objects that - * can be accessed with unambiguous stable prefixes, the implicits infos - * which are members of these companion objects. + * can be accessed with unambiguous stable prefixes that are not existentially + * bound, the implicits infos which are members of these companion objects. */ private def companionImplicitMap(tp: Type): InfoMap = { @@ -955,7 +955,7 @@ trait Implicits { infoMap(sym) = List() // ambiguous prefix - ignore implicit members } case None => - if (pre.isStable) { + if (pre.isStable && !pre.typeSymbol.isExistentiallyBound) { val companion = companionSymbolOf(sym, context) companion.moduleClass match { case mc: ModuleClassSymbol => diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 6cc536ad9b..a541906a99 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1066,22 +1066,22 @@ trait Infer extends Checkable { */ /** error if arguments not within bounds. */ def checkBounds(tree: Tree, pre: Type, owner: Symbol, - tparams: List[Symbol], targs: List[Type], prefix: String): Boolean = { - //@M validate variances & bounds of targs wrt variances & bounds of tparams - //@M TODO: better place to check this? - //@M TODO: errors for getters & setters are reported separately - val kindErrors = checkKindBounds(tparams, targs, pre, owner) - - if(!kindErrors.isEmpty) { - if (targs contains WildcardType) true - else { KindBoundErrors(tree, prefix, targs, tparams, kindErrors); false } - } else if (!isWithinBounds(pre, owner, tparams, targs)) { - if (!(targs exists (_.isErroneous)) && !(tparams exists (_.isErroneous))) { - NotWithinBounds(tree, prefix, targs, tparams, kindErrors) - false - } else true - } else true - } + tparams: List[Symbol], targs: List[Type], prefix: String): Boolean = + if ((targs exists (_.isErroneous)) || (tparams exists (_.isErroneous))) true + else { + //@M validate variances & bounds of targs wrt variances & bounds of tparams + //@M TODO: better place to check this? + //@M TODO: errors for getters & setters are reported separately + val kindErrors = checkKindBounds(tparams, targs, pre, owner) + kindErrors match { + case Nil => + def notWithinBounds() = NotWithinBounds(tree, prefix, targs, tparams, Nil) + isWithinBounds(pre, owner, tparams, targs) || {notWithinBounds(); false} + case errors => + def kindBoundErrors() = KindBoundErrors(tree, prefix, targs, tparams, errors) + (targs contains WildcardType) || {kindBoundErrors(); false} + } + } def checkKindBounds(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): List[String] = { checkKindBounds0(tparams, targs, pre, owner, true) map { diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 9a32747c3a..b5160c0519 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1361,8 +1361,7 @@ trait Namers extends MethodSynthesis { transformed(tree) = newImport // copy symbol and type attributes back into old expression // so that the structure builder will find it. - expr.symbol = expr1.symbol - expr.tpe = expr1.tpe + expr setSymbol expr1.symbol setType expr1.tpe ImportType(expr1) } } @@ -1463,8 +1462,12 @@ trait Namers extends MethodSynthesis { if (sym.isConstructor && sym.isAnyOverride) fail(OverrideConstr) - if (sym.isAbstractOverride && !sym.owner.isTrait) - fail(AbstractOverride) + if (sym.isAbstractOverride) { + if (!sym.owner.isTrait) + fail(AbstractOverride) + if(sym.isType) + fail(AbstractOverrideOnTypeMember) + } if (sym.isLazy && sym.hasFlag(PRESUPER)) fail(LazyAndEarlyInit) if (sym.info.typeSymbol == FunctionClass(0) && sym.isValueParameter && sym.owner.isCaseClass) diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index ede117f51a..dba2f25e32 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala @@ -799,8 +799,8 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL protected def spliceApply(binder: Symbol): Tree = { object splice extends Transformer { override def transform(t: Tree) = t match { - case Apply(x, List(Ident(nme.SELECTOR_DUMMY))) => - treeCopy.Apply(t, x, List(CODE.REF(binder))) + case Apply(x, List(i @ Ident(nme.SELECTOR_DUMMY))) => + treeCopy.Apply(t, x, List(CODE.REF(binder).setPos(i.pos))) case _ => super.transform(t) } } @@ -877,7 +877,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL override def transform(tree: Tree): Tree = { def subst(from: List[Symbol], to: List[Tree]): Tree = if (from.isEmpty) tree - else if (tree.symbol == from.head) typedIfOrigTyped(to.head.shallowDuplicate, tree.tpe) + else if (tree.symbol == from.head) typedIfOrigTyped(to.head.shallowDuplicate.setPos(tree.pos), tree.tpe) else subst(from.tail, to.tail) tree match { diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 396c6acd38..12562fecf8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1545,8 +1545,14 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans sym.name == nme.apply && isClassTypeAccessible(tree) - if (doTransform) + if (doTransform) { + tree foreach { + case i@Ident(_) => + enterReference(i.pos, i.symbol) // SI-5390 need to `enterReference` for `a` in `a.B()` + case _ => + } toConstructor(tree.pos, tree.tpe) + } else { ifNot tree diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala index 0a1d3bfa7a..20db479463 100644 --- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala +++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala @@ -19,16 +19,16 @@ trait StdAttachments { * by `parentTypes`. This attachment coordinates `parentTypes` and `typedTemplate` and * allows them to complete the synthesis. */ - case class SuperCallArgsAttachment(argss: List[List[Tree]]) + case class SuperArgsAttachment(argss: List[List[Tree]]) - /** Convenience method for `SuperCallArgsAttachment`. + /** Convenience method for `SuperArgsAttachment`. * Compared with `MacroRuntimeAttachment` this attachment has different a usage pattern, * so it really benefits from a dedicated extractor. */ - def superCallArgs(tree: Tree): Option[List[List[Tree]]] = - tree.attachments.get[SuperCallArgsAttachment] collect { case SuperCallArgsAttachment(argss) => argss } + def superArgs(tree: Tree): Option[List[List[Tree]]] = + tree.attachments.get[SuperArgsAttachment] collect { case SuperArgsAttachment(argss) => argss } - /** Determines whether the given tree has an associated SuperCallArgsAttachment. + /** Determines whether the given tree has an associated SuperArgsAttachment. */ - def hasSuperArgs(tree: Tree): Boolean = superCallArgs(tree).nonEmpty + def hasSuperArgs(tree: Tree): Boolean = superArgs(tree).nonEmpty }
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index fb95c952d2..260bd87fdf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -192,11 +192,8 @@ abstract class TreeCheckers extends Analyzer { override def typed(tree: Tree, mode: Int, pt: Type): Tree = returning(tree) { case EmptyTree | TypeTree() => () case _ if tree.tpe != null => - tpeOfTree.getOrElseUpdate(tree, { - val saved = tree.tpe - tree.tpe = null - saved - }) + tpeOfTree.getOrElseUpdate(tree, try tree.tpe finally tree.clearType()) + wrap(tree)(super.typed(tree, mode, pt) match { case _: Literal => () case x if x ne tree => treesDiffer(tree, x) @@ -288,7 +285,7 @@ abstract class TreeCheckers extends Analyzer { if (oldtpe =:= tree.tpe) () else typesDiffer(tree, oldtpe, tree.tpe) - tree.tpe = oldtpe + tree setType oldtpe super.traverse(tree) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 703c12038f..4fd65c18d1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -48,12 +48,13 @@ trait Typers extends Modes with Adaptations with Tags { resetContexts() resetImplicits() transformed.clear() + clearDocComments() } object UnTyper extends Traverser { override def traverse(tree: Tree) = { if (tree.canHaveAttrs) { - tree.tpe = null + tree.clearType() if (tree.hasSymbolField) tree.symbol = NoSymbol } super.traverse(tree) @@ -323,7 +324,7 @@ trait Typers extends Modes with Adaptations with Tags { def checkNonCyclic(defn: Tree, tpt: Tree) { if (!checkNonCyclic(defn.pos, tpt.tpe, defn.symbol)) { - tpt.tpe = ErrorType + tpt setType ErrorType defn.symbol.setInfo(ErrorType) } } @@ -813,7 +814,7 @@ trait Typers extends Modes with Adaptations with Tags { val tree1 = typed(resetAllAttrs(original), mode, WildcardType) // Q: `typed` already calls `addAnnotations` and `adapt`. the only difference here is that // we pass `EmptyTree` as the `original`. intended? added in 2009 (53d98e7d42) by martin. - tree1.tpe = addAnnotations(tree1, tree1.tpe) + tree1 setType addAnnotations(tree1, tree1.tpe) if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, EmptyTree) } ) @@ -931,7 +932,7 @@ trait Typers extends Modes with Adaptations with Tags { tree setSymbol overloadedExtractorOfObject tree.tpe match { - case OverloadedType(pre, alts) => tree.tpe = overloadedType(pre, alts filter (alt => hasUnapplyMember(alt.tpe))) + case OverloadedType(pre, alts) => tree setType overloadedType(pre, alts filter (alt => hasUnapplyMember(alt.tpe))) case _ => } val unapply = unapplyMember(extractor.tpe) @@ -1453,7 +1454,7 @@ trait Typers extends Modes with Adaptations with Tags { * * Returns a `TypeTree` representing a resolved parent type. * If the typechecked parent reference implies non-nullary and non-empty argument list, - * this argument list is attached to the returned value in SuperCallArgsAttachment. + * this argument list is attached to the returned value in SuperArgsAttachment. * The attachment is necessary for the subsequent typecheck to fixup a super constructor call * in the body of the primary constructor (see `typedTemplate` for details). * @@ -1519,7 +1520,7 @@ trait Typers extends Modes with Adaptations with Tags { // this is the place where we tell the typer what argss should be used for the super call // if argss are nullary or empty, then (see the docs for `typedPrimaryConstrBody`) // the super call dummy is already good enough, so we don't need to do anything - if (argssAreTrivial) supertpt else supertpt updateAttachment SuperCallArgsAttachment(argss) + if (argssAreTrivial) supertpt else supertpt updateAttachment SuperArgsAttachment(argss) } } @@ -1584,7 +1585,7 @@ trait Typers extends Modes with Adaptations with Tags { if (preSuperVals.isEmpty && preSuperStats.nonEmpty) devWarning("Wanted to zip empty presuper val list with " + preSuperStats) else - map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe) + map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt setType ldef.symbol.tpe) if (superCall1 == cunit) EmptyTree else cbody2 case _ => @@ -1604,7 +1605,7 @@ trait Typers extends Modes with Adaptations with Tags { return explode(supersupertpt, supertpt1 :: acc) } } - if (supertpt.tpe.typeSymbol == AnyClass) supertpt.tpe = AnyRefClass.tpe + if (supertpt.tpe.typeSymbol == AnyClass) supertpt setType AnyRefClass.tpe supertpt :: acc } explode(first, Nil) ++ rest @@ -1845,8 +1846,7 @@ trait Typers extends Modes with Adaptations with Tags { */ def typedTemplate(templ: Template, parents1: List[Tree]): Template = { val clazz = context.owner - // complete lazy annotations - clazz.annotations + clazz.annotations.map(_.completeInfo) if (templ.symbol == NoSymbol) templ setSymbol clazz.newLocalDummy(templ.pos) val self1 = templ.self match { @@ -1893,7 +1893,7 @@ trait Typers extends Modes with Adaptations with Tags { val primaryCtor = treeInfo.firstConstructor(body) val primaryCtor1 = primaryCtor match { case DefDef(_, _, _, _, _, Block(earlyVals :+ global.pendingSuperCall, unit)) => - val argss = superCallArgs(parents1.head) getOrElse Nil + val argss = superArgs(parents1.head) getOrElse Nil val pos = wrappingPos(parents1.head.pos, argss.flatten) val superCall = atPos(pos)(PrimarySuperCall(argss)) deriveDefDef(primaryCtor)(block => Block(earlyVals :+ superCall, unit) setPos pos) setPos pos @@ -1936,8 +1936,7 @@ trait Typers extends Modes with Adaptations with Tags { val typer1 = constrTyperIf(sym.isParameter && sym.owner.isConstructor) val typedMods = typedModifiers(vdef.mods) - // complete lazy annotations - sym.annotations + sym.annotations.map(_.completeInfo) val tpt1 = checkNoEscaping.privates(sym, typer1.typedType(vdef.tpt)) checkNonCyclic(vdef, tpt1) @@ -2165,8 +2164,7 @@ trait Typers extends Modes with Adaptations with Tags { val tparams1 = ddef.tparams mapConserve typedTypeDef val vparamss1 = ddef.vparamss mapConserve (_ mapConserve typedValDef) - // complete lazy annotations - meth.annotations + meth.annotations.map(_.completeInfo) for (vparams1 <- vparamss1; vparam1 <- vparams1 dropRight 1) if (isRepeatedParamType(vparam1.symbol.tpe)) @@ -2241,8 +2239,7 @@ trait Typers extends Modes with Adaptations with Tags { reenterTypeParams(tdef.tparams) val tparams1 = tdef.tparams mapConserve typedTypeDef val typedMods = typedModifiers(tdef.mods) - // complete lazy annotations - tdef.symbol.annotations + tdef.symbol.annotations.map(_.completeInfo) // @specialized should not be pickled when compiling with -no-specialize if (settings.nospecialization.value && currentRun.compiles(tdef.symbol)) { @@ -2278,7 +2275,7 @@ trait Typers extends Modes with Adaptations with Tags { if (!nme.isLoopHeaderLabel(ldef.symbol.name) || isPastTyper) { val restpe = ldef.symbol.tpe.resultType val rhs1 = typed(ldef.rhs, restpe) - ldef.params foreach (param => param.tpe = param.symbol.tpe) + ldef.params foreach (param => param setType param.symbol.tpe) deriveLabelDef(ldef)(_ => rhs1) setType restpe } else { @@ -2286,14 +2283,14 @@ trait Typers extends Modes with Adaptations with Tags { val rhs1 = typed(ldef.rhs) val restpe = rhs1.tpe if (restpe == initpe) { // stable result, no need to check again - ldef.params foreach (param => param.tpe = param.symbol.tpe) + ldef.params foreach (param => param setType param.symbol.tpe) treeCopy.LabelDef(ldef, ldef.name, ldef.params, rhs1) setType restpe } else { context.scope.unlink(ldef.symbol) val sym2 = namer.enterInScope( context.owner.newLabel(ldef.name, ldef.pos) setInfo MethodType(List(), restpe)) val rhs2 = typed(resetAllAttrs(ldef.rhs), restpe) - ldef.params foreach (param => param.tpe = param.symbol.tpe) + ldef.params foreach (param => param setType param.symbol.tpe) deriveLabelDef(ldef)(_ => rhs2) setSymbol sym2 setType restpe } } @@ -2399,7 +2396,7 @@ trait Typers extends Modes with Adaptations with Tags { val contextWithTypeBounds = context.nextEnclosing(_.tree.isInstanceOf[CaseDef]) if (contextWithTypeBounds.savedTypeBounds.nonEmpty) { - body1.tpe = contextWithTypeBounds restoreTypeBounds body1.tpe + body1 modifyType (contextWithTypeBounds restoreTypeBounds _) // insert a cast if something typechecked under the GADT constraints, // but not in real life (i.e., now that's we've reset the method's type skolems' @@ -2707,6 +2704,7 @@ trait Typers extends Modes with Adaptations with Tags { def typedRefinement(templ: Template) { val stats = templ.body namer.enterSyms(stats) + // need to delay rest of typedRefinement to avoid cyclic reference errors unit.toCheck += { () => val stats1 = typedStats(stats, NoSymbol) @@ -3271,7 +3269,7 @@ trait Typers extends Modes with Adaptations with Tags { else None if (!isApplicableSafe(Nil, unappType, List(pt), WildcardType)) { - //Console.println("UNAPP: need to typetest, arg.tpe = "+arg.tpe+", unappType = "+unappType) + //Console.println(s"UNAPP: need to typetest, arg: ${arg.tpe} unappType: $unappType") val (freeVars, unappFormal) = freshArgType(unappType.skolemizeExistential(context.owner, tree)) val unapplyContext = context.makeNewScope(context.tree, context.owner) freeVars foreach unapplyContext.scope.enter @@ -3281,12 +3279,12 @@ trait Typers extends Modes with Adaptations with Tags { // turn any unresolved type variables in freevars into existential skolems val skolems = freeVars map (fv => unapplyContext.owner.newExistentialSkolem(fv, fv)) - arg.tpe = pattp.substSym(freeVars, skolems) + arg setType pattp.substSym(freeVars, skolems) argDummy setInfo arg.tpe } - // setType null is necessary so that ref will be stabilized; see bug 881 - val fun1 = typedPos(fun.pos)(Apply(Select(fun setType null, unapp), List(arg))) + // clearing the type is necessary so that ref will be stabilized; see bug 881 + val fun1 = typedPos(fun.pos)(Apply(Select(fun.clearType(), unapp), List(arg))) if (fun1.tpe.isErroneous) duplErrTree else { @@ -3300,7 +3298,7 @@ trait Typers extends Modes with Adaptations with Tags { val pt1 = if (isFullyDefined(pt)) pt else makeFullyDefined(pt) // SI-1048 val itype = glb(List(pt1, arg.tpe)) - arg.tpe = pt1 // restore type (arg is a dummy tree, just needs to pass typechecking) + arg setType pt1 // restore type (arg is a dummy tree, just needs to pass typechecking) val unapply = UnApply(fun1, args1) setPos tree.pos setType itype // if the type that the unapply method expects for its argument is uncheckable, wrap in classtag extractor @@ -4013,7 +4011,7 @@ trait Typers extends Modes with Adaptations with Tags { // Erroneous annotations were already reported in typedAnnotation arg1 // simply drop erroneous annotations else { - ann.tpe = atype + ann setType atype resultingTypeTree(atype) } } else { @@ -4024,7 +4022,7 @@ trait Typers extends Modes with Adaptations with Tags { else { if (ann.tpe == null) { val annotInfo = typedAnnotation(ann, annotMode) - ann.tpe = arg1.tpe.withAnnotation(annotInfo) + ann setType arg1.tpe.withAnnotation(annotInfo) } val atype = ann.tpe Typed(arg1, resultingTypeTree(atype)) setPos tree.pos setType atype @@ -4575,7 +4573,7 @@ trait Typers extends Modes with Adaptations with Tags { NoSymbol } if (phase.erasedTypes && qual.isInstanceOf[Super] && tree.symbol != NoSymbol) - qual.tpe = tree.symbol.owner.tpe + qual setType tree.symbol.owner.tpe if (!reallyExists(sym)) { def handleMissing: Tree = { @@ -4764,7 +4762,7 @@ trait Typers extends Modes with Adaptations with Tags { typedClassOf(tree, TypeTree(pt.typeArgs.head)) else { val pre1 = if (sym.owner.isPackageClass) sym.owner.thisType else if (qual == EmptyTree) NoPrefix else qual.tpe - val tree1 = if (qual == EmptyTree) tree else atPos(tree.pos)(Select(atPos(tree.pos.focusStart)(qual), name)) + val tree1 = if (qual == EmptyTree) tree else atPos(tree.pos)(Select(atPos(tree.pos.focusStart)(qual), name) setAttachments tree.attachments) val (tree2, pre2) = makeAccessible(tree1, sym, pre1, qual) // SI-5967 Important to replace param type A* with Seq[A] when seen from from a reference, to avoid // inference errors in pattern matching. @@ -4786,14 +4784,20 @@ trait Typers extends Modes with Adaptations with Tags { def typedCompoundTypeTree(tree: CompoundTypeTree) = { val templ = tree.templ val parents1 = templ.parents mapConserve (typedType(_, mode)) - if (parents1 exists (_.isErrorTyped)) tree setType ErrorType + + // This is also checked later in typedStats, but that is too late for SI-5361, so + // we eagerly check this here. + for (stat <- templ.body if !treeInfo.isDeclarationOrTypeDef(stat)) + OnlyDeclarationsError(stat) + + if ((parents1 ++ templ.body) exists (_.isErrorTyped)) tree setType ErrorType else { val decls = newScope //Console.println("Owner: " + context.enclClass.owner + " " + context.enclClass.owner.id) val self = refinedType(parents1 map (_.tpe), context.enclClass.owner, decls, templ.pos) newTyper(context.make(templ, self.typeSymbol, decls)).typedRefinement(templ) templ updateAttachment CompoundTypeTreeOriginalAttachment(parents1, Nil) // stats are set elsewhere - tree setType self + tree setType (if (templ.exists(_.isErroneous)) ErrorType else self) // Being conservative to avoid SI-5361 } } @@ -4856,16 +4860,14 @@ trait Typers extends Modes with Adaptations with Tags { def typedPackageDef(pdef: PackageDef) = { val pid1 = typedQualifier(pdef.pid).asInstanceOf[RefTree] assert(sym.moduleClass ne NoSymbol, sym) - // complete lazy annotations - sym.annotations val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls)) .typedStats(pdef.stats, NoSymbol) treeCopy.PackageDef(tree, pid1, stats1) setType NoType } def typedDocDef(docdef: DocDef) = { - val comment = docdef.comment if (forScaladoc && (sym ne null) && (sym ne NoSymbol)) { + val comment = docdef.comment docComments(sym) = comment comment.defineVariables(sym) val typer1 = newTyper(context.makeNewScope(tree, context.owner)) @@ -5171,7 +5173,7 @@ trait Typers extends Modes with Adaptations with Tags { try { if (context.retyping && (tree.tpe ne null) && (tree.tpe.isErroneous || !(tree.tpe <:< pt))) { - tree.tpe = null + tree.clearType() if (tree.hasSymbolField) tree.symbol = NoSymbol } @@ -5195,7 +5197,7 @@ trait Typers extends Modes with Adaptations with Tags { tree1 } - tree1.tpe = addAnnotations(tree1, tree1.tpe) + tree1 modifyType (addAnnotations(tree1, _)) val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, tree) if (!alreadyTyped) { @@ -5207,7 +5209,7 @@ trait Typers extends Modes with Adaptations with Tags { result } catch { case ex: TypeError => - tree.tpe = null + tree.clearType() // The only problematic case are (recoverable) cyclic reference errors which can pop up almost anywhere. printTyping("caught %s: while typing %s".format(ex, tree)) //DEBUG diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala index f62eebaaa0..323e894b51 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala @@ -17,13 +17,14 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with import definitions._ // standard classes and methods import typer.atOwner // methods to type trees + override def description = "ANF pre-transform for @cps" + /** the following two members override abstract members in Transform */ val phaseName: String = "selectiveanf" protected def newTransformer(unit: CompilationUnit): Transformer = new ANFTransformer(unit) - class ANFTransformer(unit: CompilationUnit) extends TypingTransformer(unit) { implicit val _unit = unit // allow code in CPSUtils.scala to report errors @@ -128,7 +129,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with def transformPureMatch(tree: Tree, selector: Tree, cases: List[CaseDef]) = { val caseVals = cases map { case cd @ CaseDef(pat, guard, body) => - // if (!hasPlusMarker(body.tpe)) body.tpe = body.tpe withAnnotation newPlusMarker() // TODO: to avoid warning + // if (!hasPlusMarker(body.tpe)) body modifyType (_ withAnnotation newPlusMarker()) // TODO: to avoid warning val bodyVal = transExpr(body, None, ext) // ??? triggers "cps-transformed unexpectedly" warning in transTailValue treeCopy.CaseDef(cd, transform(pat), transform(guard), bodyVal) } diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala index 801c328177..846ce01953 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala @@ -17,6 +17,8 @@ abstract class SelectiveCPSTransform extends PluginComponent with import definitions._ // standard classes and methods import typer.atOwner // methods to type trees + override def description = "@cps-driven transform of selectiveanf assignments" + /** the following two members override abstract members in Transform */ val phaseName: String = "selectivecps" @@ -85,7 +87,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with //gen.mkAttributedSelect(gen.mkAttributedSelect(gen.mkAttributedSelect(gen.mkAttributedIdent(ScalaPackage), //ScalaPackage.tpe.member("util")), ScalaPackage.tpe.member("util").tpe.member("continuations")), MethShiftR) //gen.mkAttributedRef(ModCPS.tpe, MethShiftR) // TODO: correct? - debuglog("funR.tpe = " + funR.tpe) + debuglog("funR.tpe: " + funR.tpe) Apply( TypeApply(funR, targs).setType(appliedType(funR.tpe, targs.map((t:Tree) => t.tpe))), args.map(transform(_)) @@ -97,7 +99,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with debuglog("found shiftUnit: " + tree) atPos(tree.pos) { val funR = gen.mkAttributedRef(MethShiftUnitR) // TODO: correct? - debuglog("funR.tpe = " + funR.tpe) + debuglog("funR.tpe: " + funR.tpe) Apply( TypeApply(funR, List(targs(0), targs(1))).setType(appliedType(funR.tpe, List(targs(0).tpe, targs(1).tpe))), @@ -110,7 +112,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with log("found reify: " + tree) atPos(tree.pos) { val funR = gen.mkAttributedRef(MethReifyR) // TODO: correct? - debuglog("funR.tpe = " + funR.tpe) + debuglog("funR.tpe: " + funR.tpe) Apply( TypeApply(funR, targs).setType(appliedType(funR.tpe, targs.map((t:Tree) => t.tpe))), args.map(transform(_)) diff --git a/src/partest/scala/tools/partest/DirectTest.scala b/src/partest/scala/tools/partest/DirectTest.scala index 8c18809ad6..483cb491a1 100644 --- a/src/partest/scala/tools/partest/DirectTest.scala +++ b/src/partest/scala/tools/partest/DirectTest.scala @@ -39,6 +39,10 @@ abstract class DirectTest extends App { // new compiler def newCompiler(args: String*): Global = { val settings = newSettings((CommandLineParser tokenize ("-d \"" + testOutput.path + "\" " + extraSettings)) ++ args.toList) + newCompiler(settings) + } + + def newCompiler(settings: Settings): Global = { if (settings.Yrangepos.value) new Global(settings, reporter(settings)) with interactive.RangePositions else new Global(settings, reporter(settings)) } diff --git a/src/partest/scala/tools/partest/ScaladocModelTest.scala b/src/partest/scala/tools/partest/ScaladocModelTest.scala index acaddff944..3db9f18484 100644 --- a/src/partest/scala/tools/partest/ScaladocModelTest.scala +++ b/src/partest/scala/tools/partest/ScaladocModelTest.scala @@ -10,7 +10,7 @@ import scala.tools.nsc.util.CommandLineParser import scala.tools.nsc.doc.{Settings, DocFactory, Universe} import scala.tools.nsc.doc.model._ import scala.tools.nsc.doc.model.diagram._ -import scala.tools.nsc.doc.model.comment._ +import scala.tools.nsc.doc.base.comment._ import scala.tools.nsc.reporters.ConsoleReporter /** A class for testing scaladoc model generation diff --git a/src/partest/scala/tools/partest/javaagent/ASMTransformer.java b/src/partest/scala/tools/partest/javaagent/ASMTransformer.java index b6bec2f598..878c8613d5 100644 --- a/src/partest/scala/tools/partest/javaagent/ASMTransformer.java +++ b/src/partest/scala/tools/partest/javaagent/ASMTransformer.java @@ -26,35 +26,18 @@ public class ASMTransformer implements ClassFileTransformer { className.startsWith("instrumented/")); } - public byte[] transform(final ClassLoader classLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + public byte[] transform(final ClassLoader classLoader, final String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { if (shouldTransform(className)) { - ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { - // this is copied verbatim from the superclass, - // except that we use the outer class loader - @Override protected String getCommonSuperClass(final String type1, final String type2) { - Class<?> c, d; - try { - c = Class.forName(type1.replace('/', '.'), false, classLoader); - d = Class.forName(type2.replace('/', '.'), false, classLoader); - } catch (Exception e) { - throw new RuntimeException(e.toString()); - } - if (c.isAssignableFrom(d)) { - return type1; - } - if (d.isAssignableFrom(c)) { - return type2; - } - if (c.isInterface() || d.isInterface()) { - return "java/lang/Object"; - } else { - do { - c = c.getSuperclass(); - } while (!c.isAssignableFrom(d)); - return c.getName().replace('.', '/'); - } - } - }; + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS) { + @Override protected String getCommonSuperClass(final String type1, final String type2) { + // Since we are not recomputing stack frame map, this should never be called we override this method because + // default implementation uses reflection for implementation and might try to load the class that we are + // currently processing. That leads to weird results like swallowed exceptions and classes being not + // transformed. + throw new RuntimeException("Unexpected call to getCommonSuperClass(" + type1 + ", " + type2 + + ") while transforming " + className); + } + }; ProfilerVisitor visitor = new ProfilerVisitor(writer); ClassReader reader = new ClassReader(classfileBuffer); reader.accept(visitor, 0); diff --git a/src/partest/scala/tools/partest/javaagent/ProfilerVisitor.java b/src/partest/scala/tools/partest/javaagent/ProfilerVisitor.java index ac83f66506..8306327b14 100644 --- a/src/partest/scala/tools/partest/javaagent/ProfilerVisitor.java +++ b/src/partest/scala/tools/partest/javaagent/ProfilerVisitor.java @@ -33,6 +33,19 @@ public class ProfilerVisitor extends ClassVisitor implements Opcodes { // only instrument non-abstract methods if((access & ACC_ABSTRACT) == 0) { assert(className != null); + /* The following instructions do not modify compressed stack frame map so + * we don't need to worry about recalculating stack frame map. Specifically, + * let's quote "ASM 4.0, A Java bytecode engineering library" guide (p. 40): + * + * In order to save space, a compiled method does not contain one frame per + * instruction: in fact it contains only the frames for the instructions + * that correspond to jump targets or exception handlers, or that follow + * unconditional jump instructions. Indeed the other frames can be easily + * and quickly inferred from these ones. + * + * Instructions below are just loading constants and calling a method so according + * to definition above they do not contribute to compressed stack frame map. + */ mv.visitLdcInsn(className); mv.visitLdcInsn(name); mv.visitLdcInsn(desc); diff --git a/src/partest/scala/tools/partest/javaagent/ProfilingAgent.java b/src/partest/scala/tools/partest/javaagent/ProfilingAgent.java index c2e4dc69f4..3b18987040 100644 --- a/src/partest/scala/tools/partest/javaagent/ProfilingAgent.java +++ b/src/partest/scala/tools/partest/javaagent/ProfilingAgent.java @@ -20,6 +20,6 @@ public class ProfilingAgent { // and the test-case itself won't be loaded yet. We rely here on the fact that ASMTransformer does // not depend on Scala library. In case our assumptions are wrong we can always insert call to // inst.retransformClasses. - inst.addTransformer(new ASMTransformer(), true); + inst.addTransformer(new ASMTransformer(), false); } } diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala index 3f005d143e..9a48c5ce2b 100644 --- a/src/partest/scala/tools/partest/nest/CompileManager.scala +++ b/src/partest/scala/tools/partest/nest/CompileManager.scala @@ -9,7 +9,7 @@ package scala.tools.partest package nest import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError, io } -import scala.tools.nsc.io.{ File => SFile } +import scala.reflect.io.{ Directory, File => SFile, FileOperationException } import scala.tools.nsc.interactive.RangePositions import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter } import scala.tools.nsc.util.{ ClassPath, FakePos } @@ -70,10 +70,27 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { s } - private def updatePluginPath(options: String): String = { - def absolutize(path: String) = Path(path) match { + implicit class Copier(f: SFile) { + // But what if f is bigger than CHUNK?! + def copyTo(dest: Path) { + dest.toFile writeAll f.slurp + } + } + + // plugin path can be relative to test root, or cwd is out + private def updatePluginPath(options: String, out: Option[File], srcdir: Directory): String = { + val dir = fileManager.testRootDir + def pathOrCwd(p: String) = + if (p == "." && out.isDefined) { + val plugxml = "scalac-plugin.xml" + val pout = Path(out.get) + val pd = (srcdir / plugxml).toFile + if (pd.exists) pd copyTo (pout / plugxml) + pout + } else Path(p) + def absolutize(path: String) = pathOrCwd(path) match { case x if x.isAbsolute => x.path - case x => (fileManager.testRootDir / x).toAbsolute.path + case x => (dir / x).toAbsolute.path } val (opt1, opt2) = (options split "\\s").toList partition (_ startsWith "-Xplugin:") @@ -90,17 +107,21 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { } val logWriter = new FileWriter(log) + // this api has no notion of srcdir, so fake it + val fstFile = SFile(files(0)) + val srcdir = fstFile.parent + // check whether there is a ".flags" file + def convertFlags(f: SFile) = updatePluginPath(f.slurp(), out, srcdir) val logFile = basename(log.getName) val flagsFileName = "%s.flags" format (logFile.substring(0, logFile.lastIndexOf("-"))) - val argString = (io.File(log).parent / flagsFileName) ifFile (x => updatePluginPath(x.slurp())) getOrElse "" + val argString = (SFile(log).parent / flagsFileName) ifFile (convertFlags) getOrElse "" // slurp local flags (e.g., "A_1.flags") - val fstFile = SFile(files(0)) def isInGroup(num: Int) = fstFile.stripExtension endsWith ("_" + num) val inGroup = (1 to 9) flatMap (group => if (isInGroup(group)) List(group) else List()) val localFlagsList = if (inGroup.nonEmpty) { - val localArgString = (fstFile.parent / (fstFile.stripExtension + ".flags")) ifFile (x => updatePluginPath(x.slurp())) getOrElse "" + val localArgString = (srcdir / (fstFile.stripExtension + ".flags")) ifFile (convertFlags) getOrElse "" localArgString.split(' ').toList.filter(_.length > 0) } else List() @@ -140,8 +161,10 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { NestUI.verbose("compiling "+toCompile) NestUI.verbose("with classpath: "+global.classPath.toString) NestUI.verbose("and java classpath: "+ propOrEmpty("java.class.path")) - try new global.Run compile toCompile - catch { + try { + if (command.shouldStopWithInfo) logWriter append (command getInfoMessage global) + else new global.Run compile toCompile + } catch { case FatalError(msg) => testRep.error(null, "fatal error: " + msg) return CompilerCrashed @@ -152,7 +175,7 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { } finally logWriter.close() - if (testRep.hasErrors) CompileFailed + if (testRep.hasErrors || command.shouldStopWithInfo) CompileFailed else CompileSuccess } } diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala index d3a40718c6..3446dd0f72 100644 --- a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala +++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala @@ -81,6 +81,9 @@ class ReflectiveRunner { val newClasspath = ClassPath.join(paths: _*) setProp("java.class.path", newClasspath) + + // don't let partest find pluginsdir; in ant build, standard plugin has dedicated test suite + //setProp("scala.home", latestLibFile.parent.parent.path) setProp("scala.home", "") if (isPartestDebug) diff --git a/src/partest/scala/tools/partest/nest/RunnerManager.scala b/src/partest/scala/tools/partest/nest/RunnerManager.scala index f2ce19a950..fbef97dab4 100644 --- a/src/partest/scala/tools/partest/nest/RunnerManager.scala +++ b/src/partest/scala/tools/partest/nest/RunnerManager.scala @@ -344,21 +344,22 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP * compiler expects and how to implement them. (see SI-1240 for the full story) * * In practice, this happens in 3 steps: - * STEP1: feed all the files to scalac - * it will parse java files and obtain their expected signatures and generate bytecode for scala files - * STEP2: feed the java files to javac - * it will generate the bytecode for the java files and link to the scalac-generated bytecode for scala - * STEP3: only if there are both scala and java files, recompile the scala sources so they link to the correct + * STEP1: Feed all the files to scalac if there are also non-Scala sources. + * It will parse java files and obtain their expected signatures and generate bytecode for scala files + * STEP2: Feed the java files to javac if there are any. + * It will generate the bytecode for the java files and link to the scalac-generated bytecode for scala + * STEP3: (Re-)compile the scala sources so they link to the correct * java signatures, in case the signatures deduced by scalac from the source files were wrong. Since the * bytecode for java is already in place, we only feed the scala files to scalac so it will take the - * java signatures from the existing javac-generated bytecode + * java signatures from the existing javac-generated bytecode. + * Note that no artifacts are deleted before this step. */ List(1, 2, 3).foldLeft(CompileSuccess: CompilationOutcome) { - case (CompileSuccess, 1) if scalaFiles.nonEmpty => + case (CompileSuccess, 1) if scalaFiles.nonEmpty && javaFiles.nonEmpty => compileMgr.attemptCompile(Some(outDir), allFiles, kind, logFile) case (CompileSuccess, 2) if javaFiles.nonEmpty => javac(outDir, javaFiles, logFile) - case (CompileSuccess, 3) if scalaFiles.nonEmpty && javaFiles.nonEmpty => + case (CompileSuccess, 3) if scalaFiles.nonEmpty => // TODO: Do we actually need this? SI-1240 is known to require this, but we don't know if other tests // require it: https://groups.google.com/forum/?fromgroups#!topic/scala-internals/rFDKAcOKciU compileMgr.attemptCompile(Some(outDir), scalaFiles, kind, logFile) diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index b53c700701..a4a4277239 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -245,7 +245,7 @@ trait Symbols { self: Universe => /** Does this symbol represent the definition of a term? * Note that every symbol is either a term or a type. * So for every symbol `sym` (except for `NoSymbol`), - * either `sym.isTerm` is true or `sym.isTerm` is true. + * either `sym.isTerm` is true or `sym.isType` is true. * * @group Tests */ diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index da50c55fe1..cfa4bdf44c 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -200,6 +200,8 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => override def toString = if (forced) forcedInfo.toString else "@<?>" override def pos: Position = if (forced) forcedInfo.pos else NoPosition + + override def completeInfo(): Unit = forcedInfo } /** Typed information about an annotation. It can be attached to either @@ -241,6 +243,9 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => this } + // Forces LazyAnnotationInfo, no op otherwise + def completeInfo(): Unit = () + /** Annotations annotating annotations are confusing so I drew * an example. Given the following code: * diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index 61906740a0..654dbd76e7 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -275,7 +275,7 @@ class Flags extends ModifierFlags { * Getters of immutable values also get STABLE. */ final val GetterFlags = ~(PRESUPER | MUTABLE) - final val SetterFlags = ~(PRESUPER | MUTABLE | STABLE | CASEACCESSOR) + final val SetterFlags = ~(PRESUPER | MUTABLE | STABLE | CASEACCESSOR | IMPLICIT) /** When a symbol for a default getter is created, it inherits these * flags from the method with the default. Other flags applied at creation diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala index 29f1c7e1ca..53410b29c5 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -439,7 +439,7 @@ trait Importers extends api.Importers { self: SymbolTable => if (tt.original != null) mytt.setOriginal(importTree(tt.original)) case _ => if (mytree.hasSymbolField) mytree.symbol = importSymbol(tree.symbol) - mytree.tpe = importType(tree.tpe) + mytree setType importType(tree.tpe) } } }) diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala index 04f1d73360..b1cfaa4774 100644 --- a/src/reflect/scala/reflect/internal/Scopes.scala +++ b/src/reflect/scala/reflect/internal/Scopes.scala @@ -10,8 +10,8 @@ trait Scopes extends api.Scopes { self: SymbolTable => /** An ADT to represent the results of symbol name lookups. */ - sealed trait NameLookup { def symbol: Symbol } - case class LookupSucceeded(qualifier: Tree, symbol: Symbol) extends NameLookup + sealed trait NameLookup { def symbol: Symbol ; def isSuccess = false } + case class LookupSucceeded(qualifier: Tree, symbol: Symbol) extends NameLookup { override def isSuccess = true } case class LookupAmbiguous(msg: String) extends NameLookup { def symbol = NoSymbol } case class LookupInaccessible(symbol: Symbol, msg: String) extends NameLookup case object LookupNotFound extends NameLookup { def symbol = NoSymbol } diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala index 1df91a67b0..b782353ed3 100644 --- a/src/reflect/scala/reflect/internal/StdAttachments.scala +++ b/src/reflect/scala/reflect/internal/StdAttachments.scala @@ -10,6 +10,7 @@ trait StdAttachments { trait Attachable { protected var rawatt: scala.reflect.macros.Attachments { type Pos = Position } = NoPosition def attachments = rawatt + def setAttachments(attachments: scala.reflect.macros.Attachments { type Pos = Position }): this.type = { rawatt = attachments; this } def updateAttachment[T: ClassTag](attachment: T): this.type = { rawatt = rawatt.update(attachment); this } def removeAttachment[T: ClassTag]: this.type = { rawatt = rawatt.remove[T]; this } diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 8e776b8590..fd5c3909b8 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -2632,8 +2632,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => * * {{{ * tsym is an instance of AbstractTypeSymbol - * tsym.info = TypeBounds(Nothing, Number) - * tsym.tpe = TypeRef(NoPrefix, T, List()) + * tsym.info == TypeBounds(Nothing, Number) + * tsym.tpe == TypeRef(NoPrefix, T, List()) * }}} */ class AbstractTypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName) diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index f3aa37bd15..0954432c77 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -128,9 +128,9 @@ abstract class TreeGen extends macros.TreeBuilder { else mkAttributedIdent(sym) /** Replaces tree type with a stable type if possible */ - def stabilize(tree: Tree): Tree = { - for(tp <- stableTypeFor(tree)) tree.tpe = tp - tree + def stabilize(tree: Tree): Tree = stableTypeFor(tree) match { + case Some(tp) => tree setType tp + case _ => tree } /** Computes stable type for a tree if possible */ diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 6dc1ff157c..9e737528d2 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -24,7 +24,9 @@ trait Trees extends api.Trees { self: SymbolTable => private[this] var rawtpe: Type = _ final def tpe = rawtpe - def tpe_=(t: Type) = rawtpe = t + @deprecated("Use setType", "2.11.0") def tpe_=(t: Type): Unit = setType(t) + + def clearType(): this.type = this setType null def setType(tp: Type): this.type = { rawtpe = tp; this } def defineType(tp: Type): this.type = setType(tp) @@ -822,7 +824,7 @@ trait Trees extends api.Trees { self: SymbolTable => } def Annotated(tree: Tree, annot: Tree, arg: Tree) = tree match { case t @ Annotated(annot0, arg0) - if (annot0==annot) => t + if (annot0==annot && arg0==arg) => t case _ => treeCopy.Annotated(tree, annot, arg) } def SingletonTypeTree(tree: Tree, ref: Tree) = tree match { @@ -1402,7 +1404,7 @@ trait Trees extends api.Trees { self: SymbolTable => class ThisSubstituter(clazz: Symbol, to: => Tree) extends Transformer { val newtpe = to.tpe override def transform(tree: Tree) = { - if (tree.tpe ne null) tree.tpe = tree.tpe.substThis(clazz, newtpe) + tree modifyType (_.substThis(clazz, newtpe)) tree match { case This(_) if tree.symbol == clazz => to case _ => super.transform(tree) @@ -1412,8 +1414,7 @@ trait Trees extends api.Trees { self: SymbolTable => class TypeMapTreeSubstituter(val typeMap: TypeMap) extends Traverser { override def traverse(tree: Tree) { - if (tree.tpe ne null) - tree.tpe = typeMap(tree.tpe) + tree modifyType typeMap if (tree.isDef) tree.symbol modifyInfo typeMap @@ -1445,8 +1446,8 @@ trait Trees extends api.Trees { self: SymbolTable => if (tree.symbol == from.head) tree setSymbol to.head else subst(from.tail, to.tail) } + tree modifyType symSubst - if (tree.tpe ne null) tree.tpe = symSubst(tree.tpe) if (tree.hasSymbolField) { subst(from, to) tree match { diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 58dd7f3a03..282d7e18ac 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -6321,11 +6321,11 @@ trait Types extends api.Types { self: SymbolTable => case ExistentialType(qs, _) => qs case t => List() } - def stripType(tp: Type) = tp match { + def stripType(tp: Type): Type = tp match { case ExistentialType(_, res) => res case tv@TypeVar(_, constr) => - if (tv.instValid) constr.inst + if (tv.instValid) stripType(constr.inst) else if (tv.untouchable) tv else abort("trying to do lub/glb of typevar "+tp) case t => t diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala index 4e76f7c408..31f3192a85 100644 --- a/src/reflect/scala/reflect/macros/Universe.scala +++ b/src/reflect/scala/reflect/macros/Universe.scala @@ -114,7 +114,7 @@ abstract class Universe extends scala.reflect.api.Universe { def setPos(newpos: Position): Tree /** Sets the `tpe` of the tree. Returns `Unit`. */ - def tpe_=(t: Type): Unit + @deprecated("Use setType", "2.11.0") def tpe_=(t: Type): Unit /** Sets the `tpe` of the tree. Returns the tree itself. */ def setType(tp: Type): Tree @@ -238,4 +238,4 @@ abstract class Universe extends scala.reflect.api.Universe { /** The AST that corresponds to this compilation unit. */ def body: Tree } -}
\ No newline at end of file +} diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index f6ce19e1d7..57cfb8b515 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -568,7 +568,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni case None => // class does not have a Scala signature; it's a Java class info("translating reflection info for Java " + jclazz) //debug - initClassModule(clazz, module, new FromJavaClassCompleter(clazz, module, jclazz)) + initClassAndModule(clazz, module, new FromJavaClassCompleter(clazz, module, jclazz)) } } } catch { @@ -670,9 +670,9 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni def enter(sym: Symbol, mods: Int) = (if (jModifier.isStatic(mods)) module.moduleClass else clazz).info.decls enter sym - for (jinner <- jclazz.getDeclaredClasses) { - enter(jclassAsScala(jinner, clazz), jinner.getModifiers) - } + for (jinner <- jclazz.getDeclaredClasses) + jclassAsScala(jinner) // inner class is entered as a side-effect + // no need to call enter explicitly pendingLoadActions = { () => @@ -1016,14 +1016,15 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni * @param jclazz The Java class * @return A Scala class symbol that wraps all reflection info of `jclazz` */ - private def jclassAsScala(jclazz: jClass[_]): Symbol = jclassAsScala(jclazz, sOwner(jclazz)) + private def jclassAsScala(jclazz: jClass[_]): ClassSymbol = + toScala(classCache, jclazz)(_ jclassAsScala1 _) - private def jclassAsScala(jclazz: jClass[_], owner: Symbol): ClassSymbol = { + private def jclassAsScala1(jclazz: jClass[_]): ClassSymbol = { + val owner = sOwner(jclazz) val name = scalaSimpleName(jclazz) val completer = (clazz: Symbol, module: Symbol) => new FromJavaClassCompleter(clazz, module, jclazz) - val (clazz, _) = createClassModule(owner, name, completer) - classCache enter (jclazz, clazz) - clazz + + initAndEnterClassAndModule(owner, name, completer)._1 } /** diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index 60b22afd18..ea14e8ad43 100644 --- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala +++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala @@ -57,7 +57,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => * @param name The simple name of the newly created class * @param completer The completer to be used to set the info of the class and the module */ - protected def createClassModule(owner: Symbol, name: TypeName, completer: (Symbol, Symbol) => LazyType) = { + protected def initAndEnterClassAndModule(owner: Symbol, name: TypeName, completer: (Symbol, Symbol) => LazyType) = { assert(!(name.toString endsWith "[]"), name) val clazz = owner.newClass(name) val module = owner.newModule(name.toTermName) @@ -67,7 +67,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => owner.info.decls enter clazz owner.info.decls enter module } - initClassModule(clazz, module, completer(clazz, module)) + initClassAndModule(clazz, module, completer(clazz, module)) (clazz, module) } @@ -75,7 +75,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => List(clazz, module, module.moduleClass) foreach (_ setInfo info) } - protected def initClassModule(clazz: Symbol, module: Symbol, completer: LazyType) = + protected def initClassAndModule(clazz: Symbol, module: Symbol, completer: LazyType) = setAllInfos(clazz, module, completer) /** The type completer for packages. @@ -118,7 +118,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => val loadingMirror = currentMirror.mirrorDefining(cls) val (_, module) = if (loadingMirror eq currentMirror) { - createClassModule(pkgClass, name.toTypeName, new TopClassCompleter(_, _)) + initAndEnterClassAndModule(pkgClass, name.toTypeName, new TopClassCompleter(_, _)) } else { val origOwner = loadingMirror.packageNameToScala(pkgClass.fullName) val clazz = origOwner.info decl name.toTypeName diff --git a/test/files/lib/javac-artifacts.jar.desired.sha1 b/test/files/lib/javac-artifacts.jar.desired.sha1 index 8dbbc1d451..a49c986386 100644 --- a/test/files/lib/javac-artifacts.jar.desired.sha1 +++ b/test/files/lib/javac-artifacts.jar.desired.sha1 @@ -1 +1 @@ -c5788c5e518eb267445c5a995fd98b2210f90a58 ?javac-artifacts.jar +61931a51bb1a2d308d214b96d06e9a8808515dcf ?javac-artifacts.jar diff --git a/test/files/neg/t3222.check b/test/files/neg/t3222.check index e724024f45..6170827cc9 100644 --- a/test/files/neg/t3222.check +++ b/test/files/neg/t3222.check @@ -1,7 +1,13 @@ -t3222.scala:4: error: not found: type D - def foo(@throws(classOf[D]) x: Int) {} - ^ t3222.scala:1: error: not found: type B @throws(classOf[B]) ^ -two errors found +t3222.scala:4: error: not found: type D + def foo(@throws(classOf[D]) x: Int) {} + ^ +t3222.scala:3: error: not found: type C + @throws(classOf[C]) + ^ +t3222.scala:6: error: not found: type E + @throws(classOf[E]) + ^ +four errors found diff --git a/test/files/neg/t3614.check b/test/files/neg/t3614.check index 0f9c83aa0d..81628ef37f 100644 --- a/test/files/neg/t3614.check +++ b/test/files/neg/t3614.check @@ -1,4 +1,4 @@ -t3614.scala:2: error: class type required but AnyRef{def a: Int} found +t3614.scala:2: error: only declarations allowed here def v = new ({ def a=0 }) - ^ + ^ one error found diff --git a/test/files/neg/t3995.check b/test/files/neg/t3995.check new file mode 100644 index 0000000000..00ecf4ca5b --- /dev/null +++ b/test/files/neg/t3995.check @@ -0,0 +1,6 @@ +t3995.scala:31: error: type mismatch; + found : String("") + required: _1.F0 where val _1: Lift + (new Lift).apply("") + ^ +one error found diff --git a/test/files/neg/t3995.scala b/test/files/neg/t3995.scala new file mode 100644 index 0000000000..b03617ac86 --- /dev/null +++ b/test/files/neg/t3995.scala @@ -0,0 +1,32 @@ +class Lift { + def apply(f: F0) {} + + class F0 + object F0 { + implicit def f2f0(fn: String): F0 = ??? + } +} + +object Test { + val l = new Lift + val f = "" + + "": l.F0 // okay + + l.apply("") // okay + + { + val l = new Lift + l.apply("") // okay + } + + // fails trying to mkAttributedQualifier for pre = Skolem(_1 <: Lift with Singletom).F0 + // should this even have shown up in `companionImplicitMap`? It says that: + // + // "@return For those parts that refer to classes with companion objects that + // can be accessed with unambiguous stable prefixes, the implicits infos + // which are members of these companion objects." + // + // The skolem is stable, but it doen't seem much good to us + (new Lift).apply("") +} diff --git a/test/files/neg/t4044.check b/test/files/neg/t4044.check index 41a04f69b9..0e1ea4f51d 100644 --- a/test/files/neg/t4044.check +++ b/test/files/neg/t4044.check @@ -1,11 +1,6 @@ t4044.scala:9: error: AnyRef takes no type parameters, expected: one M[AnyRef] // error, (AnyRef :: *) not kind-conformant to (N :: * -> * -> *) ^ -t4044.scala:9: error: kinds of the type arguments (<error>) do not conform to the expected kinds of the type parameters (type N). -<error>'s type parameters do not match type N's expected parameters: -<none> has no type parameters, but type N has one - M[AnyRef] // error, (AnyRef :: *) not kind-conformant to (N :: * -> * -> *) - ^ t4044.scala:11: error: kinds of the type arguments (Test.A) do not conform to the expected kinds of the type parameters (type N). Test.A's type parameters do not match type N's expected parameters: type _ has no type parameters, but type O has one @@ -16,4 +11,4 @@ Test.C's type parameters do not match type N's expected parameters: type _ has one type parameter, but type _ has none M[C] // error, (C :: (* -> * -> * -> *) not kind-conformant to (N :: * -> * -> *) ^ -four errors found +three errors found diff --git a/test/files/neg/t5361.check b/test/files/neg/t5361.check new file mode 100644 index 0000000000..d7fee87ccd --- /dev/null +++ b/test/files/neg/t5361.check @@ -0,0 +1,4 @@ +t5361.scala:2: error: only declarations allowed here + val x : { val self = this } = new { self => } + ^ +one error found diff --git a/test/files/neg/t5361.scala b/test/files/neg/t5361.scala new file mode 100644 index 0000000000..1705c09df3 --- /dev/null +++ b/test/files/neg/t5361.scala @@ -0,0 +1,3 @@ +class A { + val x : { val self = this } = new { self => } +} diff --git a/test/files/neg/t5390.check b/test/files/neg/t5390.check new file mode 100644 index 0000000000..6a0129b898 --- /dev/null +++ b/test/files/neg/t5390.check @@ -0,0 +1,4 @@ +t5390.scala:7: error: forward reference extends over definition of value b + val b = a.B("") + ^ +one error found diff --git a/test/files/neg/t5390.scala b/test/files/neg/t5390.scala new file mode 100644 index 0000000000..dd628f8851 --- /dev/null +++ b/test/files/neg/t5390.scala @@ -0,0 +1,10 @@ +class A { + object B { def apply(s: String) = 0} +} + +object X { + def foo { + val b = a.B("") + val a = new A + } +}
\ No newline at end of file diff --git a/test/files/neg/t5390b.check b/test/files/neg/t5390b.check new file mode 100644 index 0000000000..cbf8fafa6b --- /dev/null +++ b/test/files/neg/t5390b.check @@ -0,0 +1,4 @@ +t5390b.scala:7: error: forward reference extends over definition of value b + val b = a.B("") + ^ +one error found diff --git a/test/files/neg/t5390b.scala b/test/files/neg/t5390b.scala new file mode 100644 index 0000000000..c3373b87d3 --- /dev/null +++ b/test/files/neg/t5390b.scala @@ -0,0 +1,10 @@ +class A { + case class B(s: String) +} + +object X { + def foo { + val b = a.B("") + val a = new A + } +}
\ No newline at end of file diff --git a/test/files/neg/t5390c.check b/test/files/neg/t5390c.check new file mode 100644 index 0000000000..f8a794d690 --- /dev/null +++ b/test/files/neg/t5390c.check @@ -0,0 +1,4 @@ +t5390c.scala:7: error: forward reference extends over definition of value b + val b = new a.B("") + ^ +one error found diff --git a/test/files/neg/t5390c.scala b/test/files/neg/t5390c.scala new file mode 100644 index 0000000000..6b11576611 --- /dev/null +++ b/test/files/neg/t5390c.scala @@ -0,0 +1,10 @@ +class A { + case class B(s: String) +} + +object X { + def foo { + val b = new a.B("") + val a = new A + } +}
\ No newline at end of file diff --git a/test/files/neg/t5390d.check b/test/files/neg/t5390d.check new file mode 100644 index 0000000000..daa29142e7 --- /dev/null +++ b/test/files/neg/t5390d.check @@ -0,0 +1,4 @@ +t5390d.scala:7: error: forward reference extends over definition of value b + val b = a.B.toString + ^ +one error found diff --git a/test/files/neg/t5390d.scala b/test/files/neg/t5390d.scala new file mode 100644 index 0000000000..7a2671b443 --- /dev/null +++ b/test/files/neg/t5390d.scala @@ -0,0 +1,10 @@ +class A { + case class B(s: String) +} + +object X { + def foo { + val b = a.B.toString + val a = new A + } +}
\ No newline at end of file diff --git a/test/files/neg/t5956.check b/test/files/neg/t5956.check index 6641dac97f..f5ae42c799 100644 --- a/test/files/neg/t5956.check +++ b/test/files/neg/t5956.check @@ -1,20 +1,7 @@ -t5956.scala:1: warning: case classes without a parameter list have been deprecated; -use either case objects or case classes with `()' as parameter list. -object O { case class C[T]; class C } - ^ -t5956.scala:2: warning: case classes without a parameter list have been deprecated; -use either case objects or case classes with `()' as parameter list. -object T { case class C[T]; case class C } - ^ -t5956.scala:2: warning: case classes without a parameter list have been deprecated; -use either case objects or case classes with `()' as parameter list. -object T { case class C[T]; case class C } - ^ t5956.scala:1: error: C is already defined as case class C -object O { case class C[T]; class C } - ^ +object O { case class C[T](); class C() } + ^ t5956.scala:2: error: C is already defined as case class C -object T { case class C[T]; case class C } - ^ -three warnings found +object T { case class C[T](); case class C() } + ^ two errors found diff --git a/test/files/neg/t5956.scala b/test/files/neg/t5956.scala index d985fa97a4..3cc10f3e19 100644 --- a/test/files/neg/t5956.scala +++ b/test/files/neg/t5956.scala @@ -1,2 +1,2 @@ -object O { case class C[T]; class C } -object T { case class C[T]; case class C } +object O { case class C[T](); class C() } +object T { case class C[T](); case class C() } diff --git a/test/files/neg/t6260.check b/test/files/neg/t6260.check index 2b7f1a8bfb..46e9bd1dfc 100644 --- a/test/files/neg/t6260.check +++ b/test/files/neg/t6260.check @@ -1,10 +1,10 @@ -t6260.scala:3: error: bridge generated for member method apply: (x$1: Box[X])Box[Y] in anonymous class $anonfun +t6260.scala:3: error: bridge generated for member method apply: (bx: Box[X])Box[Y] in anonymous class $anonfun which overrides method apply: (v1: T1)R in trait Function1 clashes with definition of the member itself; both have erased type (v1: Object)Object ((bx: Box[X]) => new Box(f(bx.x)))(this) ^ -t6260.scala:8: error: bridge generated for member method apply: (x$1: Box[X])Box[Y] in anonymous class $anonfun +t6260.scala:8: error: bridge generated for member method apply: (bx: Box[X])Box[Y] in anonymous class $anonfun which overrides method apply: (v1: T1)R in trait Function1 clashes with definition of the member itself; both have erased type (v1: Object)Object diff --git a/test/files/neg/t6446-additional.check b/test/files/neg/t6446-additional.check new file mode 100755 index 0000000000..53dd383941 --- /dev/null +++ b/test/files/neg/t6446-additional.check @@ -0,0 +1,31 @@ + phase name id description + ---------- -- ----------- + parser 1 parse source into ASTs, perform simple desugaring + namer 2 resolve names, attach symbols to named trees +packageobjects 3 load package objects + typer 4 the meat and potatoes: type the trees + patmat 5 translate match expressions +superaccessors 6 add super accessors in traits and nested classes + extmethods 7 add extension methods for inline classes + pickler 8 serialize symbol tables + refchecks 9 reference/override checking, translate nested objects + uncurry 10 uncurry, translate function values to anonymous classes + tailcalls 11 replace tail calls by jumps + specialize 12 @specialized-driven class and method specialization + explicitouter 13 this refs to outer pointers, translate patterns + erasure 14 erase types, add interfaces for traits + posterasure 15 clean up erased inline classes + lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs + lambdalift 17 move nested functions to top level + constructors 18 move field definitions into constructors + flatten 19 eliminate inner classes + mixin 20 mixin composition + cleanup 21 platform-specific cleanups, generate reflective calls + icode 22 generate portable intermediate code + inliner 23 optimization: do inlining +inlinehandlers 24 optimization: inline exception handlers + closelim 25 optimization: eliminate uncalled closures + dce 26 optimization: eliminate dead code + jvm 27 generate JVM bytecode + ploogin 28 A sample phase that does so many things it's kind of hard... + terminal 29 The last phase in the compiler chain diff --git a/test/files/neg/t6446-additional/ploogin_1.scala b/test/files/neg/t6446-additional/ploogin_1.scala new file mode 100644 index 0000000000..ed6adfc1cf --- /dev/null +++ b/test/files/neg/t6446-additional/ploogin_1.scala @@ -0,0 +1,31 @@ + +package t6446 + +import scala.tools.nsc.{ Global, Phase } +import scala.tools.nsc.plugins.{ Plugin, PluginComponent } +import scala.reflect.io.Path +import scala.reflect.io.File + +/** A test plugin. */ +class Ploogin(val global: Global) extends Plugin { + import global._ + + val name = "ploogin" + val description = "A sample plugin for testing." + val components = List[PluginComponent](TestComponent) + + private object TestComponent extends PluginComponent { + val global: Ploogin.this.global.type = Ploogin.this.global + //override val runsBefore = List("refchecks") + val runsAfter = List("jvm") + val phaseName = Ploogin.this.name + override def description = "A sample phase that does so many things it's kind of hard to describe briefly." + def newPhase(prev: Phase) = new TestPhase(prev) + class TestPhase(prev: Phase) extends StdPhase(prev) { + override def description = TestComponent.this.description + def apply(unit: CompilationUnit) { + // kewl kode + } + } + } +} diff --git a/test/files/neg/t6446-additional/sample_2.flags b/test/files/neg/t6446-additional/sample_2.flags new file mode 100644 index 0000000000..4d518c2286 --- /dev/null +++ b/test/files/neg/t6446-additional/sample_2.flags @@ -0,0 +1 @@ +-Xplugin:. -Xshow-phases diff --git a/test/files/neg/t6446-additional/sample_2.scala b/test/files/neg/t6446-additional/sample_2.scala new file mode 100644 index 0000000000..73cdc64e40 --- /dev/null +++ b/test/files/neg/t6446-additional/sample_2.scala @@ -0,0 +1,6 @@ + +package sample + +// just a sample that is compiled with the sample plugin enabled +object Sample extends App { +} diff --git a/test/files/neg/t6446-additional/scalac-plugin.xml b/test/files/neg/t6446-additional/scalac-plugin.xml new file mode 100644 index 0000000000..e849bb5919 --- /dev/null +++ b/test/files/neg/t6446-additional/scalac-plugin.xml @@ -0,0 +1,4 @@ +<plugin> +<name>sample-plugin</name> +<classname>t6446.Ploogin</classname> +</plugin> diff --git a/test/files/neg/t6446-list.check b/test/files/neg/t6446-list.check new file mode 100755 index 0000000000..fa5c581941 --- /dev/null +++ b/test/files/neg/t6446-list.check @@ -0,0 +1 @@ +ploogin - A sample plugin for testing. diff --git a/test/files/neg/t6446-list/ploogin_1.scala b/test/files/neg/t6446-list/ploogin_1.scala new file mode 100644 index 0000000000..ed6adfc1cf --- /dev/null +++ b/test/files/neg/t6446-list/ploogin_1.scala @@ -0,0 +1,31 @@ + +package t6446 + +import scala.tools.nsc.{ Global, Phase } +import scala.tools.nsc.plugins.{ Plugin, PluginComponent } +import scala.reflect.io.Path +import scala.reflect.io.File + +/** A test plugin. */ +class Ploogin(val global: Global) extends Plugin { + import global._ + + val name = "ploogin" + val description = "A sample plugin for testing." + val components = List[PluginComponent](TestComponent) + + private object TestComponent extends PluginComponent { + val global: Ploogin.this.global.type = Ploogin.this.global + //override val runsBefore = List("refchecks") + val runsAfter = List("jvm") + val phaseName = Ploogin.this.name + override def description = "A sample phase that does so many things it's kind of hard to describe briefly." + def newPhase(prev: Phase) = new TestPhase(prev) + class TestPhase(prev: Phase) extends StdPhase(prev) { + override def description = TestComponent.this.description + def apply(unit: CompilationUnit) { + // kewl kode + } + } + } +} diff --git a/test/files/neg/t6446-list/sample_2.flags b/test/files/neg/t6446-list/sample_2.flags new file mode 100644 index 0000000000..9cb3232964 --- /dev/null +++ b/test/files/neg/t6446-list/sample_2.flags @@ -0,0 +1 @@ +-Xplugin:. -Xplugin-list diff --git a/test/files/neg/t6446-list/sample_2.scala b/test/files/neg/t6446-list/sample_2.scala new file mode 100644 index 0000000000..73cdc64e40 --- /dev/null +++ b/test/files/neg/t6446-list/sample_2.scala @@ -0,0 +1,6 @@ + +package sample + +// just a sample that is compiled with the sample plugin enabled +object Sample extends App { +} diff --git a/test/files/neg/t6446-list/scalac-plugin.xml b/test/files/neg/t6446-list/scalac-plugin.xml new file mode 100644 index 0000000000..e849bb5919 --- /dev/null +++ b/test/files/neg/t6446-list/scalac-plugin.xml @@ -0,0 +1,4 @@ +<plugin> +<name>sample-plugin</name> +<classname>t6446.Ploogin</classname> +</plugin> diff --git a/test/files/neg/t6446-missing.check b/test/files/neg/t6446-missing.check new file mode 100755 index 0000000000..f976bf480e --- /dev/null +++ b/test/files/neg/t6446-missing.check @@ -0,0 +1,31 @@ +Warning: class not found: t6446.Ploogin + phase name id description + ---------- -- ----------- + parser 1 parse source into ASTs, perform simple desugaring + namer 2 resolve names, attach symbols to named trees +packageobjects 3 load package objects + typer 4 the meat and potatoes: type the trees + patmat 5 translate match expressions +superaccessors 6 add super accessors in traits and nested classes + extmethods 7 add extension methods for inline classes + pickler 8 serialize symbol tables + refchecks 9 reference/override checking, translate nested objects + uncurry 10 uncurry, translate function values to anonymous classes + tailcalls 11 replace tail calls by jumps + specialize 12 @specialized-driven class and method specialization + explicitouter 13 this refs to outer pointers, translate patterns + erasure 14 erase types, add interfaces for traits + posterasure 15 clean up erased inline classes + lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs + lambdalift 17 move nested functions to top level + constructors 18 move field definitions into constructors + flatten 19 eliminate inner classes + mixin 20 mixin composition + cleanup 21 platform-specific cleanups, generate reflective calls + icode 22 generate portable intermediate code + inliner 23 optimization: do inlining +inlinehandlers 24 optimization: inline exception handlers + closelim 25 optimization: eliminate uncalled closures + dce 26 optimization: eliminate dead code + jvm 27 generate JVM bytecode + terminal 28 The last phase in the compiler chain diff --git a/test/files/neg/t6446-missing/sample_2.flags b/test/files/neg/t6446-missing/sample_2.flags new file mode 100644 index 0000000000..4d518c2286 --- /dev/null +++ b/test/files/neg/t6446-missing/sample_2.flags @@ -0,0 +1 @@ +-Xplugin:. -Xshow-phases diff --git a/test/files/neg/t6446-missing/sample_2.scala b/test/files/neg/t6446-missing/sample_2.scala new file mode 100644 index 0000000000..73cdc64e40 --- /dev/null +++ b/test/files/neg/t6446-missing/sample_2.scala @@ -0,0 +1,6 @@ + +package sample + +// just a sample that is compiled with the sample plugin enabled +object Sample extends App { +} diff --git a/test/files/neg/t6446-missing/scalac-plugin.xml b/test/files/neg/t6446-missing/scalac-plugin.xml new file mode 100644 index 0000000000..9c34d63f83 --- /dev/null +++ b/test/files/neg/t6446-missing/scalac-plugin.xml @@ -0,0 +1,4 @@ +<plugin> +<name>missing-plugin</name> +<classname>t6446.Ploogin</classname> +</plugin> diff --git a/test/files/neg/t6446-show-phases.check b/test/files/neg/t6446-show-phases.check new file mode 100644 index 0000000000..5bbe43990c --- /dev/null +++ b/test/files/neg/t6446-show-phases.check @@ -0,0 +1,30 @@ + phase name id description + ---------- -- ----------- + parser 1 parse source into ASTs, perform simple desugaring + namer 2 resolve names, attach symbols to named trees +packageobjects 3 load package objects + typer 4 the meat and potatoes: type the trees + patmat 5 translate match expressions +superaccessors 6 add super accessors in traits and nested classes + extmethods 7 add extension methods for inline classes + pickler 8 serialize symbol tables + refchecks 9 reference/override checking, translate nested objects + uncurry 10 uncurry, translate function values to anonymous classes + tailcalls 11 replace tail calls by jumps + specialize 12 @specialized-driven class and method specialization + explicitouter 13 this refs to outer pointers, translate patterns + erasure 14 erase types, add interfaces for traits + posterasure 15 clean up erased inline classes + lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs + lambdalift 17 move nested functions to top level + constructors 18 move field definitions into constructors + flatten 19 eliminate inner classes + mixin 20 mixin composition + cleanup 21 platform-specific cleanups, generate reflective calls + icode 22 generate portable intermediate code + inliner 23 optimization: do inlining +inlinehandlers 24 optimization: inline exception handlers + closelim 25 optimization: eliminate uncalled closures + dce 26 optimization: eliminate dead code + jvm 27 generate JVM bytecode + terminal 28 The last phase in the compiler chain diff --git a/test/files/neg/t6446-show-phases.flags b/test/files/neg/t6446-show-phases.flags new file mode 100644 index 0000000000..845666e100 --- /dev/null +++ b/test/files/neg/t6446-show-phases.flags @@ -0,0 +1 @@ +-Xshow-phases diff --git a/test/files/neg/t6446-show-phases.scala b/test/files/neg/t6446-show-phases.scala new file mode 100644 index 0000000000..a9afb042d2 --- /dev/null +++ b/test/files/neg/t6446-show-phases.scala @@ -0,0 +1,3 @@ + +// testing compiler flag output only +object Test extends App diff --git a/test/files/neg/t6558.check b/test/files/neg/t6558.check index 1b39ef9986..6ad3cecd50 100644 --- a/test/files/neg/t6558.check +++ b/test/files/neg/t6558.check @@ -1,10 +1,10 @@ -t6558.scala:19: error: not found: type classs +t6558.scala:4: error: not found: type classs @classs ^ -t6558.scala:22: error: not found: type typeparam +t6558.scala:7: error: not found: type typeparam class D[@typeparam T] ^ -t6558.scala:25: error: not found: type valueparam +t6558.scala:10: error: not found: type valueparam @valueparam x: Any ^ three errors found diff --git a/test/files/neg/t6558.scala b/test/files/neg/t6558.scala index bdc441698f..b4304ff686 100644 --- a/test/files/neg/t6558.scala +++ b/test/files/neg/t6558.scala @@ -1,21 +1,6 @@ class AnnotNotFound { def foo(a: Any) = () - foo { - // Not yet issued in the context of this file, see SI-6758 - // This error is issued in t6558b.scala - @inargument - def foo = 0 - foo - } - - () => { - // As per above - @infunction - def foo = 0 - () - } - @classs class C diff --git a/test/files/neg/t6758.check b/test/files/neg/t6758.check new file mode 100644 index 0000000000..2cdd6b8ae5 --- /dev/null +++ b/test/files/neg/t6758.check @@ -0,0 +1,28 @@ +t6758.scala:5: error: not found: type inargument + @inargument + ^ +t6758.scala:11: error: not found: type infunction + @infunction + ^ +t6758.scala:18: error: not found: type nested + @nested + ^ +t6758.scala:25: error: not found: type param + def func(@param x: Int): Int = 0 + ^ +t6758.scala:28: error: not found: type typealias + @typealias + ^ +t6758.scala:32: error: not found: type classs + @classs + ^ +t6758.scala:35: error: not found: type module + @module + ^ +t6758.scala:38: error: not found: type typeparam + class D[@typeparam T] + ^ +t6758.scala:41: error: not found: type valueparam + @valueparam x: Any + ^ +9 errors found diff --git a/test/files/neg/t6758.scala b/test/files/neg/t6758.scala new file mode 100644 index 0000000000..acf333bf90 --- /dev/null +++ b/test/files/neg/t6758.scala @@ -0,0 +1,43 @@ +class AnnotNotFound { + def foo(a: Any) = () + + foo { + @inargument + def foo = 0 + foo + } + + () => { + @infunction + def foo = 0 + () + } + + () => { + val bar: Int = { + @nested + val bar2: Int = 2 + 2 + } + () + } + + def func(@param x: Int): Int = 0 + + abstract class A { + @typealias + type B = Int + } + + @classs + class C + + @module + object D + + class D[@typeparam T] + + class E( + @valueparam x: Any + ) +} diff --git a/test/files/neg/t6795.check b/test/files/neg/t6795.check new file mode 100644 index 0000000000..88ef3e9a52 --- /dev/null +++ b/test/files/neg/t6795.check @@ -0,0 +1,4 @@ +t6795.scala:3: error: `abstract override' modifier not allowed for type members +trait T1 extends T { abstract override type U = Int } + ^ +one error found diff --git a/test/files/neg/t6795.scala b/test/files/neg/t6795.scala new file mode 100644 index 0000000000..a523c89c82 --- /dev/null +++ b/test/files/neg/t6795.scala @@ -0,0 +1,3 @@ +trait T { type U } +// "abstract override" shouldn't be allowed on types +trait T1 extends T { abstract override type U = Int } diff --git a/test/files/pos/annotated-treecopy.check b/test/files/pos/annotated-treecopy.check new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/files/pos/annotated-treecopy.check diff --git a/test/files/pos/annotated-treecopy.flags b/test/files/pos/annotated-treecopy.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/pos/annotated-treecopy.flags @@ -0,0 +1 @@ +-language:experimental.macros
\ No newline at end of file diff --git a/test/files/pos/annotated-treecopy/Impls_Macros_1.scala b/test/files/pos/annotated-treecopy/Impls_Macros_1.scala new file mode 100644 index 0000000000..d92fbca380 --- /dev/null +++ b/test/files/pos/annotated-treecopy/Impls_Macros_1.scala @@ -0,0 +1,53 @@ +import scala.language.experimental.macros +import scala.reflect.macros.Context +import collection.mutable.ListBuffer +import collection.mutable.Stack + +object Macros { + trait TypedFunction { + def tree: scala.reflect.runtime.universe.Tree + val typeIn: String + val typeOut: String + } + + def tree[T,U](f:Function1[T,U]): Function1[T,U] = macro tree_impl[T,U] + + def tree_impl[T:c.WeakTypeTag,U:c.WeakTypeTag](c: Context) + (f:c.Expr[Function1[T,U]]): c.Expr[Function1[T,U]] = { + import c.universe._ + val ttag = c.weakTypeTag[U] + f match { + case Expr(Function(List(ValDef(_,n,tp,_)),b)) => + // normalize argument name + var b1 = new Transformer { + override def transform(tree: Tree): Tree = tree match { + case Ident(x) if (x==n) => Ident(newTermName("_arg")) + case tt @ TypeTree() if tt.original != null => TypeTree(tt.tpe) setOriginal transform(tt.original) + // without the fix to LazyTreeCopier.Annotated, we would need to uncomment the line below to make the macro work + // that's because the pattern match in the input expression gets expanded into Typed(<x>, TypeTree(<Int @unchecked>)) + // with the original of the TypeTree being Annotated(<@unchecked>, Ident(<x>)) + // then the macro tries to replace all Ident(<x>) trees with Ident(<_arg>), recurs into the original of the TypeTree, changes it, + // but leaves the <@unchecked> part untouched. this signals the misguided LazyTreeCopier that the Annotated tree hasn't been modified, + // so the original tree should be copied over and returned => crash when later <x: @unchecked> re-emerges from TypeTree.original + // case Annotated(annot, arg) => treeCopy.Annotated(tree, transform(annot).duplicate, transform(arg)) + case _ => super.transform(tree) + } + }.transform(b) + + val reifiedTree = c.reifyTree(treeBuild.mkRuntimeUniverseRef, EmptyTree, b1) + val reifiedExpr = c.Expr[scala.reflect.runtime.universe.Expr[T => U]](reifiedTree) + val template = + c.universe.reify(new (T => U) with TypedFunction { + override def toString = c.literal(tp+" => "+ttag.tpe+" { "+b1.toString+" } ").splice // DEBUG + def tree = reifiedExpr.splice.tree + val typeIn = c.literal(tp.toString).splice + val typeOut = c.literal(ttag.tpe.toString).splice + def apply(_arg: T): U = c.Expr[U](b1)(ttag.asInstanceOf[c.WeakTypeTag[U]]).splice + }) + val untyped = c.resetLocalAttrs(template.tree) + + c.Expr[T => U](untyped) + case _ => sys.error("Bad function type") + } + } +}
\ No newline at end of file diff --git a/test/files/pos/annotated-treecopy/Test_2.scala b/test/files/pos/annotated-treecopy/Test_2.scala new file mode 100644 index 0000000000..836e0d888d --- /dev/null +++ b/test/files/pos/annotated-treecopy/Test_2.scala @@ -0,0 +1,5 @@ +object Test extends App { + import Macros._ + // tree { (x:((Int,Int,Int),(Int,Int,Int))) => { val y=x; val ((r1,m1,c1),(r2,m2,c2))=y; (r1, m1 + m2 + r1 * c1 * c2, c2) } } + tree { (x:((Int,Int,Int),(Int,Int,Int))) => { val ((r1,m1,c1),(r2,m2,c2))=x; (r1, m1 + m2 + r1 * c1 * c2, c2) } } +}
\ No newline at end of file diff --git a/test/files/pos/attachments-typed-ident.check b/test/files/pos/attachments-typed-ident.check new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/files/pos/attachments-typed-ident.check diff --git a/test/files/pos/attachments-typed-ident.flags b/test/files/pos/attachments-typed-ident.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/pos/attachments-typed-ident.flags @@ -0,0 +1 @@ +-language:experimental.macros
\ No newline at end of file diff --git a/test/files/pos/attachments-typed-ident/Impls_1.scala b/test/files/pos/attachments-typed-ident/Impls_1.scala new file mode 100644 index 0000000000..cc40893a93 --- /dev/null +++ b/test/files/pos/attachments-typed-ident/Impls_1.scala @@ -0,0 +1,17 @@ +import scala.reflect.macros.Context +import language.experimental.macros + +object MyAttachment + +object Macros { + def impl(c: Context) = { + import c.universe._ + val ident = Ident(newTermName("bar")) updateAttachment MyAttachment + assert(ident.attachments.get[MyAttachment.type].isDefined, ident.attachments) + val typed = c.typeCheck(ident) + assert(typed.attachments.get[MyAttachment.type].isDefined, typed.attachments) + c.Expr[Int](typed) + } + + def foo = macro impl +}
\ No newline at end of file diff --git a/test/files/pos/attachments-typed-ident/Macros_Test_2.scala b/test/files/pos/attachments-typed-ident/Macros_Test_2.scala new file mode 100644 index 0000000000..37065ead4b --- /dev/null +++ b/test/files/pos/attachments-typed-ident/Macros_Test_2.scala @@ -0,0 +1,4 @@ +object Test extends App { + def bar = 2 + Macros.foo +}
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_oopsla_session_simpler.scala b/test/files/pos/depmet_implicit_oopsla_session_simpler.scala index d2986ef56f..7c9af66611 100644 --- a/test/files/pos/depmet_implicit_oopsla_session_simpler.scala +++ b/test/files/pos/depmet_implicit_oopsla_session_simpler.scala @@ -5,7 +5,7 @@ object Sessions { def run(dp: Dual): Unit } - sealed case class Stop extends Session { + sealed case class Stop() extends Session { type Dual = Stop def run(dp: Dual): Unit = {} diff --git a/test/files/pos/infer2-pos.scala b/test/files/pos/infer2-pos.scala index 06d0f5814f..0ed9666f40 100644 --- a/test/files/pos/infer2-pos.scala +++ b/test/files/pos/infer2-pos.scala @@ -1,7 +1,7 @@ package test class Lst[T] case class cons[T](x: T, xs: Lst[T]) extends Lst[T] -case class nil[T] extends Lst[T] +case class nil[T]() extends Lst[T] object test { Console.println(cons(1, nil())) } diff --git a/test/files/pos/setter-not-implicit.flags b/test/files/pos/setter-not-implicit.flags new file mode 100644 index 0000000000..792c40565b --- /dev/null +++ b/test/files/pos/setter-not-implicit.flags @@ -0,0 +1 @@ +-feature -Xfatal-warnings
\ No newline at end of file diff --git a/test/files/pos/setter-not-implicit.scala b/test/files/pos/setter-not-implicit.scala new file mode 100644 index 0000000000..9bfffc2ceb --- /dev/null +++ b/test/files/pos/setter-not-implicit.scala @@ -0,0 +1,3 @@ +object O { + implicit var x: Int = 0 +} diff --git a/test/files/pos/strip-tvars-for-lubbasetypes.scala b/test/files/pos/strip-tvars-for-lubbasetypes.scala new file mode 100644 index 0000000000..2be8625bae --- /dev/null +++ b/test/files/pos/strip-tvars-for-lubbasetypes.scala @@ -0,0 +1,25 @@ +object Test { + + implicit final class EqualOps[T](val x: T) extends AnyVal { + def ===[T1, Ph >: T <: T1, Ph2 >: Ph <: T1](other: T1): Boolean = x == other + def !!![T1, Ph2 >: Ph <: T1, Ph >: T <: T1](other: T1): Boolean = x == other + } + + class A + class B extends A + class C extends A + + val a = new A + val b = new B + val c = new C + + val x1 = a === b + val x2 = b === a + val x3 = b === c // error, infers Object{} for T1 + val x4 = b.===[A, B, B](c) + + val x5 = b !!! c // always compiled due to the order of Ph2 and Ph + + + +} diff --git a/test/files/pos/t0301.scala b/test/files/pos/t0301.scala index cb68f38062..24b4776010 100644 --- a/test/files/pos/t0301.scala +++ b/test/files/pos/t0301.scala @@ -1,7 +1,7 @@ package fos abstract class Expr -case class Var extends Expr +case class Var() extends Expr object Analyzer { def substitution(expr: Expr, cls: (Var,Var)): Expr = diff --git a/test/files/pos/t344.scala b/test/files/pos/t344.scala index 8a6ad9120d..449a763af7 100644 --- a/test/files/pos/t344.scala +++ b/test/files/pos/t344.scala @@ -1,7 +1,7 @@ object Bug { class A; - case class A1 extends A; - case class A2 extends A; + case class A1() extends A; + case class A2() extends A; def f: A = if (true) A1() diff --git a/test/files/pos/t5390.scala b/test/files/pos/t5390.scala new file mode 100644 index 0000000000..36febb6a58 --- /dev/null +++ b/test/files/pos/t5390.scala @@ -0,0 +1,11 @@ +class A { + case class B[A](s: String) +} + +object X { + def foo { + val a = new A + val b = new a.B[c.type]("") // not a forward reference + val c = "" + } +}
\ No newline at end of file diff --git a/test/files/pos/t911.scala b/test/files/pos/t911.scala index 224b14cda3..cfa4f49dc1 100644 --- a/test/files/pos/t911.scala +++ b/test/files/pos/t911.scala @@ -1,6 +1,6 @@ object Test { -def foo : Any = { - case class Foo {} - Foo; -} + def foo: Any = { + case class Foo() {} + Foo; + } } diff --git a/test/files/presentation/doc.check b/test/files/presentation/doc.check new file mode 100755 index 0000000000..62b3bfc2e3 --- /dev/null +++ b/test/files/presentation/doc.check @@ -0,0 +1,48 @@ +body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text( +)))))) +@example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba))))))))) +@version: +@since: +@todo: +@note: +@see: +body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text( +)))))) +@example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba))))))))) +@version:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(1), Text(.)))), Text(0, 09/07/2012)))))) +@since: +@todo: +@note: +@see: +body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text( +)))))) +@example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba))))))))) +@version:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(1), Text(.)))), Text(0, 09/07/2012)))))) +@since:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(2), Text(.)))), Text(10)))))) +@todo: +@note: +@see: +body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text( +)))))) +@example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba))))))))) +@version:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(1), Text(.)))), Text(0, 09/07/2012)))))) +@since:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(2), Text(.)))), Text(10)))))) +@todo:Body(List(Paragraph(Chain(List(Summary(Text(this method is unsafe))))))) +@note: +@see: +body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text( +)))))) +@example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba))))))))) +@version:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(1), Text(.)))), Text(0, 09/07/2012)))))) +@since:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(2), Text(.)))), Text(10)))))) +@todo:Body(List(Paragraph(Chain(List(Summary(Text(this method is unsafe))))))) +@note:Body(List(Paragraph(Chain(List(Summary(Text(Don't inherit!))))))) +@see: +body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text( +)))))) +@example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba))))))))) +@version:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(1), Text(.)))), Text(0, 09/07/2012)))))) +@since:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(2), Text(.)))), Text(10)))))) +@todo:Body(List(Paragraph(Chain(List(Summary(Text(this method is unsafe))))))) +@note:Body(List(Paragraph(Chain(List(Summary(Text(Don't inherit!))))))) +@see:Body(List(Paragraph(Chain(List(Summary(Text(some other method))))))) diff --git a/test/files/presentation/doc.scala b/test/files/presentation/doc.scala new file mode 100755 index 0000000000..4b0d6baa1f --- /dev/null +++ b/test/files/presentation/doc.scala @@ -0,0 +1,71 @@ +import scala.tools.nsc.doc +import scala.tools.nsc.doc.base.LinkTo +import scala.tools.nsc.doc.base.comment._ +import scala.tools.nsc.interactive._ +import scala.tools.nsc.interactive.tests._ +import scala.tools.nsc.util._ +import scala.tools.nsc.io._ + +object Test extends InteractiveTest { + override val settings: doc.Settings = docSettings + + val tags = Seq( + "@example `\"abb\".permutations = Iterator(abb, bab, bba)`", + "@version 1.0, 09/07/2012", + "@since 2.10", + "@todo this method is unsafe", + "@note Don't inherit!", + "@see some other method" + ) + + val comment = "This is a test comment." + val caret = "<caret>" + + def text(nTags: Int) = + """|/** %s + | + | * %s */ + |trait Commented {} + |class User(c: %sCommented)""".stripMargin.format(comment, tags take nTags mkString "\n", caret) + + override def main(args: Array[String]) { + val documenter = new Doc(settings) { + val global: compiler.type = compiler + + def chooseLink(links: List[LinkTo]): LinkTo = links.head + } + for (i <- 1 to tags.length) { + val markedText = text(i) + val idx = markedText.indexOf(caret) + val fileText = markedText.substring(0, idx) + markedText.substring(idx + caret.length) + val source = sourceFiles(0) + val batch = new BatchSourceFile(source.file, fileText.toCharArray) + val reloadResponse = new Response[Unit] + compiler.askReload(List(batch), reloadResponse) + reloadResponse.get.left.toOption match { + case None => + reporter.println("Couldn't reload") + case Some(_) => + val treeResponse = new compiler.Response[compiler.Tree] + val pos = compiler.rangePos(batch, idx, idx, idx) + compiler.askTypeAt(pos, treeResponse) + treeResponse.get.left.toOption match { + case Some(tree) => + val sym = tree.tpe.typeSymbol + documenter.retrieve(sym, sym.owner) match { + case Some(HtmlResult(comment)) => + import comment._ + val tags: List[(String, Iterable[Body])] = + List(("@example", example), ("@version", version), ("@since", since.toList), ("@todo", todo), ("@note", note), ("@see", see)) + val str = ("body:" + body + "\n") + + tags.map{ case (name, bodies) => name + ":" + bodies.mkString("\n") }.mkString("\n") + reporter.println(str) + case Some(_) => reporter.println("Got unexpected result") + case None => reporter.println("Got no result") + } + case None => reporter.println("Couldn't find a typedTree") + } + } + } + } +} diff --git a/test/files/presentation/doc/src/Test.scala b/test/files/presentation/doc/src/Test.scala new file mode 100755 index 0000000000..fcc1554994 --- /dev/null +++ b/test/files/presentation/doc/src/Test.scala @@ -0,0 +1 @@ +object Test
\ No newline at end of file diff --git a/test/files/presentation/memory-leaks/MemoryLeaksTest.scala b/test/files/presentation/memory-leaks/MemoryLeaksTest.scala index a5533a623a..159097cc10 100644 --- a/test/files/presentation/memory-leaks/MemoryLeaksTest.scala +++ b/test/files/presentation/memory-leaks/MemoryLeaksTest.scala @@ -5,6 +5,7 @@ import java.util.Calendar import scala.tools.nsc.interactive.tests._ import scala.tools.nsc.util._ import scala.tools.nsc.io._ +import scala.tools.nsc.doc /** This test runs the presentation compiler on the Scala compiler project itself and records memory consumption. * @@ -24,6 +25,8 @@ import scala.tools.nsc.io._ object Test extends InteractiveTest { final val mega = 1024 * 1024 + override val settings: doc.Settings = docSettings + override def execute(): Unit = memoryConsumptionTest() def batchSource(name: String) = @@ -120,4 +123,4 @@ object Test extends InteractiveTest { r.totalMemory() - r.freeMemory() } -}
\ No newline at end of file +} diff --git a/test/files/run/caseclasses.scala b/test/files/run/caseclasses.scala index 5aafea59e3..668c984f3d 100644 --- a/test/files/run/caseclasses.scala +++ b/test/files/run/caseclasses.scala @@ -1,6 +1,6 @@ case class Foo(x: Int)(y: Int) -case class Bar +case class Bar() abstract class Base abstract case class Abs(x: Int) extends Base diff --git a/test/files/run/inline-ex-handlers.check b/test/files/run/inline-ex-handlers.check index e786c780d6..45db7c3a15 100644 --- a/test/files/run/inline-ex-handlers.check +++ b/test/files/run/inline-ex-handlers.check @@ -47,7 +47,7 @@ < 106 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) -> ? CALL_METHOD MyException.message (dynamic) +> 106 CALL_METHOD MyException.message (dynamic) 502c504 < blocks: [1,2,3,4,6,7,8,9,10] --- @@ -162,12 +162,12 @@ < 176 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) -> ? CALL_METHOD MyException.message (dynamic) +> 176 CALL_METHOD MyException.message (dynamic) 783c833,834 < 177 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) -> ? CALL_METHOD MyException.message (dynamic) +> 177 CALL_METHOD MyException.message (dynamic) 785c836,837 < 177 THROW(MyException) --- @@ -194,12 +194,12 @@ < 181 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) -> ? CALL_METHOD MyException.message (dynamic) +> 181 CALL_METHOD MyException.message (dynamic) 822c878,879 < 182 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) -> ? CALL_METHOD MyException.message (dynamic) +> 182 CALL_METHOD MyException.message (dynamic) 824c881,882 < 182 THROW(MyException) --- @@ -260,7 +260,7 @@ < 127 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) -> ? CALL_METHOD MyException.message (dynamic) +> 127 CALL_METHOD MyException.message (dynamic) 966c1042 < catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 11, 14, 16, 17, 19) starting at: 3 --- @@ -299,7 +299,7 @@ < 154 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) -> ? CALL_METHOD MyException.message (dynamic) +> 154 CALL_METHOD MyException.message (dynamic) 1275c1354 < blocks: [1,2,3,4,5,7] --- @@ -354,22 +354,23 @@ < 213 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) -> ? CALL_METHOD MyException.message (dynamic) +> 213 CALL_METHOD MyException.message (dynamic) 1470c1560 < blocks: [1,2,3,4,5,7] --- > blocks: [1,2,3,4,5,7,8] -1494c1584,1591 +1494c1584,1585 < 58 THROW(IllegalArgumentException) --- > ? STORE_LOCAL(value e) > ? JUMP 8 -> +1495a1587,1592 > 8: > 62 LOAD_MODULE object Predef > 62 CONSTANT("RuntimeException") > 62 CALL_METHOD scala.Predef.println (dynamic) > 62 JUMP 2 +> 1543c1640 < blocks: [1,2,3,4] --- diff --git a/test/files/run/inline-ex-handlers.scala b/test/files/run/inline-ex-handlers.scala index a96b938e13..33e794b940 100644 --- a/test/files/run/inline-ex-handlers.scala +++ b/test/files/run/inline-ex-handlers.scala @@ -1,7 +1,7 @@ import scala.tools.partest.IcodeTest object Test extends IcodeTest { - override def printIcodeAfterPhase = "inlineExceptionHandlers" + override def printIcodeAfterPhase = "inlinehandlers" } import scala.util.Random._ diff --git a/test/files/run/no-pickle-skolems.check b/test/files/run/no-pickle-skolems.check new file mode 100644 index 0000000000..d64066171a --- /dev/null +++ b/test/files/run/no-pickle-skolems.check @@ -0,0 +1 @@ +OK! diff --git a/test/files/run/no-pickle-skolems/Source_1.scala b/test/files/run/no-pickle-skolems/Source_1.scala new file mode 100644 index 0000000000..1b4cbfa788 --- /dev/null +++ b/test/files/run/no-pickle-skolems/Source_1.scala @@ -0,0 +1,5 @@ +package s + +trait Foo { def to[CC[X]](implicit cc: CC[Int]): Unit } + +class Bar extends Foo { def to[CC[X]](implicit cc: CC[Int]): Unit = ??? } diff --git a/test/files/run/no-pickle-skolems/Test_2.scala b/test/files/run/no-pickle-skolems/Test_2.scala new file mode 100644 index 0000000000..90bb4c4f88 --- /dev/null +++ b/test/files/run/no-pickle-skolems/Test_2.scala @@ -0,0 +1,37 @@ +import scala.reflect.runtime.universe._ + +object Test { + /** Collects symbols by the given name, even if they're not + * named CC. + */ + def collectSymbols[T: TypeTag](inMethod: TermName, name: String): List[String] = { + val m = typeOf[T] member inMethod typeSignatureIn typeOf[T] + var buf: List[Symbol] = Nil + var seen: Set[Symbol] = Set() + def id(s: Symbol): Int = s.asInstanceOf[{ def id: Int }].id + + def check(s: Symbol) { + if (!seen(s)) { + seen += s + if (s.name.toString == name) buf ::= s + } + } + def loop(t: Type) { + t match { + case TypeRef(pre, sym, args) => loop(pre) ; check(sym) ; args foreach loop + case PolyType(tparams, restpe) => tparams foreach { tp => check(tp) ; check(tp.owner) ; loop(tp.typeSignature) } ; loop(restpe) + case MethodType(params, restpe) => params foreach { p => check(p) ; loop(p.typeSignature) } ; loop(restpe) + case _ => + } + } + loop(m) + + buf.reverse.distinct map (s => s.name + "#" + id(s)) + } + + def main(args: Array[String]): Unit = { + val syms = collectSymbols[s.Bar]("to", "CC") + assert(syms.size == 1, syms) + println("OK!") + } +} diff --git a/test/files/run/programmatic-main.check b/test/files/run/programmatic-main.check index bdf76ddce1..d472c569d2 100644 --- a/test/files/run/programmatic-main.check +++ b/test/files/run/programmatic-main.check @@ -1,31 +1,31 @@ - phase name id description - ---------- -- ----------- - parser 1 parse source into ASTs, perform simple desugaring - namer 2 resolve names, attach symbols to named trees - packageobjects 3 load package objects - typer 4 the meat and potatoes: type the trees - patmat 5 translate match expressions - superaccessors 6 add super accessors in traits and nested classes - extmethods 7 add extension methods for inline classes - pickler 8 serialize symbol tables - refchecks 9 reference/override checking, translate nested objects - uncurry 10 uncurry, translate function values to anonymous classes - tailcalls 11 replace tail calls by jumps - specialize 12 @specialized-driven class and method specialization - explicitouter 13 this refs to outer pointers, translate patterns - erasure 14 erase types, add interfaces for traits - posterasure 15 clean up erased inline classes - lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs - lambdalift 17 move nested functions to top level - constructors 18 move field definitions into constructors - flatten 19 eliminate inner classes - mixin 20 mixin composition - cleanup 21 platform-specific cleanups, generate reflective calls - icode 22 generate portable intermediate code - inliner 23 optimization: do inlining -inlineExceptionHandlers 24 optimization: inline exception handlers - closelim 25 optimization: eliminate uncalled closures - dce 26 optimization: eliminate dead code - jvm 27 generate JVM bytecode - terminal 28 The last phase in the compiler chain + phase name id description + ---------- -- ----------- + parser 1 parse source into ASTs, perform simple desugaring + namer 2 resolve names, attach symbols to named trees +packageobjects 3 load package objects + typer 4 the meat and potatoes: type the trees + patmat 5 translate match expressions +superaccessors 6 add super accessors in traits and nested classes + extmethods 7 add extension methods for inline classes + pickler 8 serialize symbol tables + refchecks 9 reference/override checking, translate nested objects + uncurry 10 uncurry, translate function values to anonymous classes + tailcalls 11 replace tail calls by jumps + specialize 12 @specialized-driven class and method specialization + explicitouter 13 this refs to outer pointers, translate patterns + erasure 14 erase types, add interfaces for traits + posterasure 15 clean up erased inline classes + lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs + lambdalift 17 move nested functions to top level + constructors 18 move field definitions into constructors + flatten 19 eliminate inner classes + mixin 20 mixin composition + cleanup 21 platform-specific cleanups, generate reflective calls + icode 22 generate portable intermediate code + inliner 23 optimization: do inlining +inlinehandlers 24 optimization: inline exception handlers + closelim 25 optimization: eliminate uncalled closures + dce 26 optimization: eliminate dead code + jvm 27 generate JVM bytecode + terminal 28 The last phase in the compiler chain diff --git a/test/files/run/structural.scala b/test/files/run/structural.scala index 36af8c4bfc..3a703d2cf1 100644 --- a/test/files/run/structural.scala +++ b/test/files/run/structural.scala @@ -152,7 +152,7 @@ object test2 { object test3 { - case class Exc extends Exception + case class Exc() extends Exception object Rec { def f = throw Exc() diff --git a/test/files/pos/t4351.check b/test/files/run/t4351.check index cb5d407e13..cb5d407e13 100644 --- a/test/files/pos/t4351.check +++ b/test/files/run/t4351.check diff --git a/test/files/pos/t4351.scala b/test/files/run/t4351.scala index 2d57588793..d954d748b7 100644 --- a/test/files/pos/t4351.scala +++ b/test/files/run/t4351.scala @@ -1,7 +1,8 @@ object Test { def main(args: Array[String]): Unit = { - try new BooleanPropImpl() value + try new BooleanPropImpl().value catch { + // was: StackOverflowError case e: RuntimeException => println("runtime exception") } } diff --git a/test/files/run/t4415.scala b/test/files/run/t4415.scala index f96031d650..caf1609b9e 100644 --- a/test/files/run/t4415.scala +++ b/test/files/run/t4415.scala @@ -39,7 +39,7 @@ class SecondProperty extends TopProperty class SubclassSecondProperty extends StandardProperty trait MyProp[T] -case class MyPropImpl[T] extends MyProp[T] +case class MyPropImpl[T]() extends MyProp[T] object SubclassMatch { diff --git a/test/files/run/t6288.check b/test/files/run/t6288.check new file mode 100644 index 0000000000..0a8ff0b92d --- /dev/null +++ b/test/files/run/t6288.check @@ -0,0 +1,85 @@ +[[syntax trees at end of patmat]] // newSource1 +[7]package [7]<empty> { + [7]object Case3 extends [13][106]scala.AnyRef { + [106]def <init>(): [13]Case3.type = [106]{ + [106][106][106]Case3.super.<init>(); + [13]() + }; + [21]def unapply([29]z: [32]<type: [32]scala.Any>): [21]Option[Int] = [56][52][52]scala.Some.apply[[52]Int]([58]-1); + [64]{ + [64]case <synthetic> val x1: [64]Any = [64]""; + [64]case5()[84]{ + [84]<synthetic> val o7: [84]Option[Int] = [84][84]Case3.unapply([84]x1); + [84]if ([84]o7.isEmpty.unary_!) + [84]{ + [90]val nr: [90]Int = [90]o7.get; + [97][97]matchEnd4([97]()) + } + else + [84][84]case6() + }; + [64]case6(){ + [64][64]matchEnd4([64]throw [64][64][64]new [64]MatchError([64]x1)) + }; + [64]matchEnd4(x: [NoPosition]Unit){ + [64]x + } + } + }; + [113]object Case4 extends [119][217]scala.AnyRef { + [217]def <init>(): [119]Case4.type = [217]{ + [217][217][217]Case4.super.<init>(); + [119]() + }; + [127]def unapplySeq([138]z: [141]<type: [141]scala.Any>): [127]Option[List[Int]] = [167]scala.None; + [175]{ + [175]case <synthetic> val x1: [175]Any = [175]""; + [175]case5()[195]{ + [195]<synthetic> val o7: [195]Option[List[Int]] = [195][195]Case4.unapplySeq([195]x1); + [195]if ([195]o7.isEmpty.unary_!) + [195]if ([195][195][195][195]o7.get.!=([195]null).&&([195][195][195][195]o7.get.lengthCompare([195]1).==([195]0))) + [195]{ + [201]val nr: [201]Int = [201][201]o7.get.apply([201]0); + [208][208]matchEnd4([208]()) + } + else + [195][195]case6() + else + [195][195]case6() + }; + [175]case6(){ + [175][175]matchEnd4([175]throw [175][175][175]new [175]MatchError([175]x1)) + }; + [175]matchEnd4(x: [NoPosition]Unit){ + [175]x + } + } + }; + [224]object Case5 extends [230][312]scala.AnyRef { + [312]def <init>(): [230]Case5.type = [312]{ + [312][312][312]Case5.super.<init>(); + [230]() + }; + [238]def unapply([246]z: [249]<type: [249]scala.Any>): [238]Boolean = [265]true; + [273]{ + [273]case <synthetic> val x1: [273]Any = [273]""; + [273]case5()[293]{ + [293]<synthetic> val o7: [293]Option[List[Int]] = [293][293]Case4.unapplySeq([293]x1); + [293]if ([293]o7.isEmpty.unary_!) + [293]if ([293][293][293][293]o7.get.!=([293]null).&&([293][293][293][293]o7.get.lengthCompare([293]0).==([293]0))) + [304][304]matchEnd4([304]()) + else + [293][293]case6() + else + [293][293]case6() + }; + [273]case6(){ + [273][273]matchEnd4([273]throw [273][273][273]new [273]MatchError([273]x1)) + }; + [273]matchEnd4(x: [NoPosition]Unit){ + [273]x + } + } + } +} + diff --git a/test/files/run/t6288.scala b/test/files/run/t6288.scala new file mode 100644 index 0000000000..cf5865e95a --- /dev/null +++ b/test/files/run/t6288.scala @@ -0,0 +1,41 @@ +import scala.tools.partest._ +import java.io.{Console => _, _} + +object Test extends DirectTest { + + override def extraSettings: String = "-usejavacp -Xprint:patmat -Xprint-pos -d " + testOutput.path + + override def code = + """ + |object Case3 { + | def unapply(z: Any): Option[Int] = Some(-1) + | + | "" match { + | case Case3(nr) => () + | } + |} + |object Case4 { + | def unapplySeq(z: Any): Option[List[Int]] = None + | + | "" match { + | case Case4(nr) => () + | } + |} + |object Case5 { + | def unapply(z: Any): Boolean = true + | + | "" match { + | case Case4() => () + | } + |} + | + |""".stripMargin.trim + + override def show(): Unit = { + // Now: [84][84]Case3.unapply([84]x1); + // Was: [84][84]Case3.unapply([64]x1); + Console.withErr(System.out) { + compile() + } + } +} diff --git a/test/files/run/t6288b-jump-position.check b/test/files/run/t6288b-jump-position.check new file mode 100644 index 0000000000..45ec31c308 --- /dev/null +++ b/test/files/run/t6288b-jump-position.check @@ -0,0 +1,80 @@ +object Case3 extends Object { + // fields: + + // methods + def unapply(z: Object (REF(class Object))): Option { + locals: value z + startBlock: 1 + blocks: [1] + + 1: + 2 NEW REF(class Some) + 2 DUP(REF(class Some)) + 2 CONSTANT(-1) + 2 BOX INT + 2 CALL_METHOD scala.Some.<init> (static-instance) + 2 RETURN(REF(class Option)) + + } + Exception handlers: + + def main(args: Array[String] (ARRAY[REF(class String)])): Unit { + locals: value args, value x1, value x2, value x + startBlock: 1 + blocks: [1,2,3,6,7] + + 1: + 4 CONSTANT("") + 4 STORE_LOCAL(value x1) + 4 SCOPE_ENTER value x1 + 4 JUMP 2 + + 2: + 5 LOAD_LOCAL(value x1) + 5 IS_INSTANCE REF(class String) + 5 CZJUMP (BOOL)NE ? 3 : 6 + + 3: + 5 LOAD_LOCAL(value x1) + 5 CHECK_CAST REF(class String) + 5 STORE_LOCAL(value x2) + 5 SCOPE_ENTER value x2 + 6 LOAD_MODULE object Predef + 6 CONSTANT("case 0") + 6 CALL_METHOD scala.Predef.println (dynamic) + 6 LOAD_FIELD scala.runtime.BoxedUnit.UNIT + 6 STORE_LOCAL(value x) + 6 JUMP 7 + + 6: + 8 LOAD_MODULE object Predef + 8 CONSTANT("default") + 8 CALL_METHOD scala.Predef.println (dynamic) + 8 LOAD_FIELD scala.runtime.BoxedUnit.UNIT + 8 STORE_LOCAL(value x) + 8 JUMP 7 + + 7: + 10 LOAD_MODULE object Predef + 10 CONSTANT("done") + 10 CALL_METHOD scala.Predef.println (dynamic) + 10 RETURN(UNIT) + + } + Exception handlers: + + def <init>(): Case3.type { + locals: + startBlock: 1 + blocks: [1] + + 1: + 12 THIS(Case3) + 12 CALL_METHOD java.lang.Object.<init> (super()) + 12 RETURN(UNIT) + + } + Exception handlers: + + +} diff --git a/test/files/run/t6288b-jump-position.scala b/test/files/run/t6288b-jump-position.scala new file mode 100644 index 0000000000..e22a1ab120 --- /dev/null +++ b/test/files/run/t6288b-jump-position.scala @@ -0,0 +1,22 @@ +import scala.tools.partest.IcodeTest + +object Test extends IcodeTest { + override def code = + """object Case3 { // 01 + | def unapply(z: Any): Option[Int] = Some(-1) // 02 + | def main(args: Array[String]) { // 03 + | ("": Any) match { // 04 + | case x : String => // 05 Read: <linenumber> JUMP <target basic block id> + | println("case 0") // 06 expecting "6 JUMP 7", was "8 JUMP 7" + | case _ => // 07 + | println("default") // 08 expecting "8 JUMP 7" + | } // 09 + | println("done") // 10 + | } + |}""".stripMargin + + override def show() { + val lines1 = collectIcode("") + println(lines1 mkString "\n") + } +} diff --git a/test/files/run/t6548.check b/test/files/run/t6548.check new file mode 100644 index 0000000000..e82cae110a --- /dev/null +++ b/test/files/run/t6548.check @@ -0,0 +1,2 @@ +false +List(JavaAnnotationWithNestedEnum(value = VALUE)) diff --git a/test/files/run/t6548.scala b/test/files/run/t6548.scala new file mode 100644 index 0000000000..be3eb5b932 --- /dev/null +++ b/test/files/run/t6548.scala @@ -0,0 +1,12 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} + +class Bean { + @JavaAnnotationWithNestedEnum(JavaAnnotationWithNestedEnum.Value.VALUE) + def value = 1 +} + +object Test extends App { + println(cm.staticClass("Bean").isCaseClass) + println(typeOf[Bean].declaration(newTermName("value")).annotations) +} diff --git a/test/files/run/t6555.check b/test/files/run/t6555.check new file mode 100644 index 0000000000..04117b7c2f --- /dev/null +++ b/test/files/run/t6555.check @@ -0,0 +1,22 @@ +[[syntax trees at end of specialize]] // newSource1 +package <empty> { + class Foo extends Object { + def <init>(): Foo = { + Foo.super.<init>(); + () + }; + private[this] val f: Int => Int = { + @SerialVersionUID(0) final <synthetic> class $anonfun extends scala.runtime.AbstractFunction1$mcII$sp with Serializable { + def <init>(): anonymous class $anonfun = { + $anonfun.super.<init>(); + () + }; + final def apply(param: Int): Int = $anonfun.this.apply$mcII$sp(param); + <specialized> def apply$mcII$sp(param: Int): Int = param + }; + (new anonymous class $anonfun(): Int => Int) + }; + <stable> <accessor> def f(): Int => Int = Foo.this.f + } +} + diff --git a/test/files/run/t6555.scala b/test/files/run/t6555.scala new file mode 100644 index 0000000000..b1a6137786 --- /dev/null +++ b/test/files/run/t6555.scala @@ -0,0 +1,15 @@ +import scala.tools.partest._ +import java.io.{Console => _, _} + +object Test extends DirectTest { + + override def extraSettings: String = "-usejavacp -Xprint:specialize -d " + testOutput.path + + override def code = "class Foo { val f = (param: Int) => param } " + + override def show(): Unit = { + Console.withErr(System.out) { + compile() + } + } +} diff --git a/test/scaladoc/resources/Trac4325.scala b/test/scaladoc/resources/Trac4325.scala index ffb968d571..ccc2f1900a 100644 --- a/test/scaladoc/resources/Trac4325.scala +++ b/test/scaladoc/resources/Trac4325.scala @@ -1,5 +1,5 @@ -case class WithSynthetic +case class WithSynthetic() -case class WithObject +case class WithObject() object WithObject diff --git a/test/scaladoc/run/SI-191-deprecated.scala b/test/scaladoc/run/SI-191-deprecated.scala index 746aa9c598..4ed24ff8d1 100755 --- a/test/scaladoc/run/SI-191-deprecated.scala +++ b/test/scaladoc/run/SI-191-deprecated.scala @@ -1,5 +1,6 @@ import scala.tools.nsc.doc.model._ -import scala.tools.nsc.doc.model.comment._ +import scala.tools.nsc.doc.base._ +import scala.tools.nsc.doc.base.comment._ import scala.tools.partest.ScaladocModelTest import java.net.{URI, URL} import java.io.File diff --git a/test/scaladoc/run/SI-191.scala b/test/scaladoc/run/SI-191.scala index 0fb28145c3..6fb5339d66 100755 --- a/test/scaladoc/run/SI-191.scala +++ b/test/scaladoc/run/SI-191.scala @@ -1,5 +1,6 @@ import scala.tools.nsc.doc.model._ -import scala.tools.nsc.doc.model.comment._ +import scala.tools.nsc.doc.base._ +import scala.tools.nsc.doc.base.comment._ import scala.tools.partest.ScaladocModelTest import java.net.{URI, URL} import java.io.File diff --git a/test/scaladoc/run/SI-3314.scala b/test/scaladoc/run/SI-3314.scala index fe220b08af..c856fe46a8 100644 --- a/test/scaladoc/run/SI-3314.scala +++ b/test/scaladoc/run/SI-3314.scala @@ -1,3 +1,4 @@ +import scala.tools.nsc.doc.base._ import scala.tools.nsc.doc.model._ import scala.tools.partest.ScaladocModelTest @@ -88,4 +89,4 @@ object Test extends ScaladocModelTest { assert(bar.valueParams(0)(0).resultType.name == "(AnyRef { type Lambda[X] <: Either[A,X] })#Lambda[String]", bar.valueParams(0)(0).resultType.name + " == (AnyRef { type Lambda[X] <: Either[A,X] })#Lambda[String]") } -}
\ No newline at end of file +} diff --git a/test/scaladoc/run/SI-5235.scala b/test/scaladoc/run/SI-5235.scala index 6295fc7786..c6b7922bb8 100644 --- a/test/scaladoc/run/SI-5235.scala +++ b/test/scaladoc/run/SI-5235.scala @@ -1,3 +1,4 @@ +import scala.tools.nsc.doc.base._ import scala.tools.nsc.doc.model._ import scala.tools.nsc.doc.model.diagram._ import scala.tools.partest.ScaladocModelTest @@ -84,4 +85,4 @@ object Test extends ScaladocModelTest { assert(mcReverseType.refEntity(0)._1 == LinkToTpl(MyCollection), mcReverse.qualifiedName + "'s return type has a link to " + MyCollection.qualifiedName) } -}
\ No newline at end of file +} diff --git a/test/scaladoc/run/links.scala b/test/scaladoc/run/links.scala index 9fbf618558..64441c2d95 100644 --- a/test/scaladoc/run/links.scala +++ b/test/scaladoc/run/links.scala @@ -1,3 +1,4 @@ +import scala.tools.nsc.doc.base._ import scala.tools.nsc.doc.model._ import scala.tools.partest.ScaladocModelTest @@ -23,8 +24,8 @@ object Test extends ScaladocModelTest { val base = rootPackage._package("scala")._package("test")._package("scaladoc")._package("links") val TEST = base._object("TEST") - val memberLinks = countLinks(TEST.comment.get, _.link.isInstanceOf[LinkToMember]) - val templateLinks = countLinks(TEST.comment.get, _.link.isInstanceOf[LinkToTpl]) + val memberLinks = countLinks(TEST.comment.get, _.link.isInstanceOf[LinkToMember[_, _]]) + val templateLinks = countLinks(TEST.comment.get, _.link.isInstanceOf[LinkToTpl[_]]) assert(memberLinks == 18, memberLinks + " == 18 (the member links in object TEST)") assert(templateLinks == 6, templateLinks + " == 6 (the template links in object TEST)") } diff --git a/test/scaladoc/scalacheck/CommentFactoryTest.scala b/test/scaladoc/scalacheck/CommentFactoryTest.scala index 5e3141bdc0..96174d29d1 100644 --- a/test/scaladoc/scalacheck/CommentFactoryTest.scala +++ b/test/scaladoc/scalacheck/CommentFactoryTest.scala @@ -3,8 +3,7 @@ import org.scalacheck.Prop._ import scala.tools.nsc.Global import scala.tools.nsc.doc -import scala.tools.nsc.doc.model._ -import scala.tools.nsc.doc.model.comment._ +import scala.tools.nsc.doc.base.comment._ import scala.tools.nsc.doc.model._ import scala.tools.nsc.doc.model.diagram._ |