diff --git a/.mailmap b/.mailmap index 1927f85d2e..1b33a40de9 100644 --- a/.mailmap +++ b/.mailmap @@ -1,7 +1,27 @@ -Aleksandar Prokopec -Aleksandar Prokopec -Aleksandar Prokopec -Aleksandar Prokopec Aleksandar Prokopec +Aleksandar Prokopec +Aleksandar Prokopec +Aleksandar Prokopec +Aleksandar Prokopec +Antonio Cunei +Caoyuan Deng +Chris Hodapp +Chris James +Christopher Vogt +Damien Obristi Daniel C. Sobral +Daniel C. Sobral +Ilya Sergei +Ingo Maier +Kenji Yoshida <6b656e6a69@gmail.com> +Luc Bourlier +Martin Odersky +Nada Amin +Nada Amin +Natallie Baikevich Pavel Pavlov +Pavel Pavlov +Philipp Haller +Roland Kuhn +Rüdiger Klaehn +Stéphane Micheloud diff --git a/build.xml b/build.xml index 0052b8914d..6048f0f3fa 100644 --- a/build.xml +++ b/build.xml @@ -2503,6 +2503,7 @@ Binary compatibility testing + @@ -2518,7 +2519,19 @@ Binary compatibility testing - + + + + + + + + + + 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..75f38c7d67 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 ----------------------------------------- @@ -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 @@ -1038,37 +1039,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 + 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) ) - ) + 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 } + currentRun.supplementedError = true + + ("\n" + info1) :: info2 :: info3 mkString "\n\n" + } + catch { case x: Exception => errorMessage } /** The id of the currently active run */ @@ -1122,6 +1127,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] @@ -1478,7 +1486,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", "") - 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", "") + 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/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/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 old mode 100644 new mode 100755 similarity index 89% rename from src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala rename to src/compiler/scala/tools/nsc/doc/base/CommentFactoryBase.scala index c798def4cb..30f33e48c9 --- 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 old mode 100644 new mode 100755 similarity index 99% rename from src/compiler/scala/tools/nsc/doc/model/comment/Body.scala rename to src/compiler/scala/tools/nsc/doc/base/comment/Body.scala index 8848af95eb..2a07547de2 --- 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 similarity index 99% rename from src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala rename to 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) { inlineToHtml(text) } else { inlineToHtml(text) } - case LinkToMember(mbr, inTpl) => + case LinkToMember(mbr: MemberEntity, inTpl: TemplateEntity) => if (hasLinks) { inlineToHtml(text) } else @@ -140,7 +141,7 @@ abstract class HtmlPage extends Page { thisPage => { inlineToHtml(text) } case LinkToExternal(name, url) => { inlineToHtml(text) } - 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 -

{ memberToUseCaseCommentHtml(mbr, isSelf) }{ inlineToHtml(mbr.comment.get.short) }

- } + def memberToShortCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = + mbr.comment.fold(NodeSeq.Empty) { comment => +

{ memberToUseCaseCommentHtml(mbr, isSelf) }{ inlineToHtml(comment.short) }

+ } def memberToInlineCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq =

{ inlineToHtml(mbr.comment.get.short) }

@@ -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 = { -
{ tp.name }
{ bodyToHtml(mbrCmt.typeParams(tp.name)) }
+
{ tp.name }
{ bodyToHtml(comment.typeParams(tp.name)) }
} - paramEntry ++ paramCommentToHtml(rest) + paramEntry ++ paramCommentToHtml(rest, comment) case (vp: ValueParam) :: rest => val paramEntry: NodeSeq = { -
{ vp.name }
{ bodyToHtml(mbrCmt.valueParams(vp.name)) }
+
{ vp.name }
{ bodyToHtml(comment.valueParams(vp.name)) }
} - 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 {
{ - paramCommentToHtml(cmtedPrs) ++ ( - mbrCmt.result match { + paramCommentToHtml(cmtedPrs, comment) ++ ( + comment.result match { case None => NodeSeq.Empty case Some(cmt) =>
returns
{ bodyToHtml(cmt) }
@@ -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 =>
@@ -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) =>
Self Type
{ typeToHtml(dtpl.selfType.get, hasLinks = true) }
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
Source
@@ -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 { -
Deprecated
-
{ bodyToHtml(mbr.deprecation.get) }
+ val deprecation: NodeSeq = + mbr.deprecation match { + case Some(deprecation) if !isReduced => +
Deprecated
+
{ bodyToHtml(deprecation) }
+ 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 =>
Migration
-
{ bodyToHtml(mbr.migration.get) }
+
{ bodyToHtml(migration) }
+ 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) {
Example{ if (comment.example.length > 1) "s" else ""}: -
    { - val exampleXml: List[scala.xml.NodeSeq] = - for(example <- comment.example ) yield -
  1. { bodyToHtml(example) }
  2. - exampleXml.reduceLeft(_ ++ Text(", ") ++ _) +
      { + val exampleXml: List[NodeSeq] = for (ex <- comment.example) yield +
    1. { bodyToHtml(ex) }
    2. + exampleXml.reduceLeft(_ ++ Text(", ") ++ _) }
    -
- else NodeSeq.Empty +
+ } - val version: Seq[scala.xml.Node] = - if(!comment.version.isEmpty) { + val version: NodeSeq = + orEmpty(comment.version) {
Version
-
{ for(body <- comment.version.toList) yield {bodyToHtml(body)} }
- } else NodeSeq.Empty +
{ for(body <- comment.version.toList) yield bodyToHtml(body) }
+ } - val sinceVersion: Seq[scala.xml.Node] = - if(!comment.since.isEmpty) { + val sinceVersion: NodeSeq = + orEmpty(comment.since) {
Since
-
{ for(body <- comment.since.toList) yield {bodyToHtml(body)} }
- } else NodeSeq.Empty +
{ for(body <- comment.since.toList) yield bodyToHtml(body) }
+ } - val note: Seq[scala.xml.Node] = - if(!comment.note.isEmpty) { + val note: NodeSeq = + orEmpty(comment.note) {
Note
{ - val noteXml: List[scala.xml.NodeSeq] = (for(note <- comment.note ) yield {bodyToHtml(note)} ) + val noteXml: List[NodeSeq] = for(note <- comment.note ) yield {bodyToHtml(note)} noteXml.reduceLeft(_ ++ Text(", ") ++ _) }
- } else NodeSeq.Empty + } - val seeAlso: Seq[scala.xml.Node] = - if(!comment.see.isEmpty) { + val seeAlso: NodeSeq = + orEmpty(comment.see) {
See also
{ - val seeXml:List[scala.xml.NodeSeq]=(for(see <- comment.see ) yield {bodyToHtml(see)} ) + val seeXml: List[NodeSeq] = for(see <- comment.see ) yield {bodyToHtml(see)} seeXml.reduceLeft(_ ++ _) }
- } else NodeSeq.Empty + } - val exceptions: Seq[scala.xml.Node] = - if(!comment.throws.isEmpty) { + val exceptions: NodeSeq = + orEmpty(comment.throws) {
Exceptions thrown
{ - val exceptionsXml: Iterable[scala.xml.NodeSeq] = - for(exception <- comment.throws.toList.sortBy(_._1) ) yield - {Text(exception._1) ++ bodyToHtml(exception._2)} + val exceptionsXml: List[NodeSeq] = + for((name, body) <- comment.throws.toList.sortBy(_._1) ) yield + {Text(name) ++ bodyToHtml(body)} exceptionsXml.reduceLeft(_ ++ Text("") ++ _) }
- } else NodeSeq.Empty + } - val todo: Seq[scala.xml.Node] = - if(!comment.todo.isEmpty) { + val todo: NodeSeq = + orEmpty(comment.todo) {
To do
{ - val todoXml: List[scala.xml.NodeSeq] = (for(todo <- comment.todo ) yield {bodyToHtml(todo)} ) + val todoXml: List[NodeSeq] = (for(todo <- comment.todo ) yield {bodyToHtml(todo)} ) todoXml.reduceLeft(_ ++ Text(", ") ++ _) }
- } 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 + 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)) } - 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" - } - 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 + override def chooseLink(links: List[LinkTo]): LinkTo = { + val mbrs = links.collect { + case lm@LinkToMember(mbr: MemberEntity, _) => (mbr, lm) } - } - - 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 - } - } - //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..a34ebb2b8c 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -70,6 +70,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/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 8e274f7647..9715dd3d44 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -993,6 +993,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 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 fe93a0ea76..27944b8767 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -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/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 d524c88f43..b5160c0519 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1462,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/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index f243569dc8..2b01e32497 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -48,6 +48,7 @@ trait Typers extends Modes with Adaptations with Tags { resetContexts() resetImplicits() transformed.clear() + clearDocComments() } object UnTyper extends Traverser { @@ -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) } } @@ -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)) { @@ -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) @@ -4769,7 +4767,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. @@ -4791,14 +4789,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 } } @@ -4861,16 +4865,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)) 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/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/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/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 024e1b30bf..9e737528d2 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -824,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 { 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/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 () do not conform to the expected kinds of the type parameters (type N). -'s type parameters do not match type N's expected parameters: - 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/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/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 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(, TypeTree()) + // with the original of the TypeTree being Annotated(<@unchecked>, Ident()) + // then the macro tries to replace all Ident() 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 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 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/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/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/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 = "" + + 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/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/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] { + [7]object Case3 extends [13][106]scala.AnyRef { + [106]def (): [13]Case3.type = [106]{ + [106][106][106]Case3.super.(); + [13]() + }; + [21]def unapply([29]z: [32]): [21]Option[Int] = [56][52][52]scala.Some.apply[[52]Int]([58]-1); + [64]{ + [64]case val x1: [64]Any = [64]""; + [64]case5()[84]{ + [84] 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 (): [119]Case4.type = [217]{ + [217][217][217]Case4.super.(); + [119]() + }; + [127]def unapplySeq([138]z: [141]): [127]Option[List[Int]] = [167]scala.None; + [175]{ + [175]case val x1: [175]Any = [175]""; + [175]case5()[195]{ + [195] 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 (): [230]Case5.type = [312]{ + [312][312][312]Case5.super.(); + [230]() + }; + [238]def unapply([246]z: [249]): [238]Boolean = [265]true; + [273]{ + [273]case val x1: [273]Any = [273]""; + [273]case5()[293]{ + [293] 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. (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 (): Case3.type { + locals: + startBlock: 1 + blocks: [1] + + 1: + 12 THIS(Case3) + 12 CALL_METHOD java.lang.Object. (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: JUMP + | 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 { + class Foo extends Object { + def (): Foo = { + Foo.super.(); + () + }; + private[this] val f: Int => Int = { + @SerialVersionUID(0) final class $anonfun extends scala.runtime.AbstractFunction1$mcII$sp with Serializable { + def (): anonymous class $anonfun = { + $anonfun.super.(); + () + }; + final def apply(param: Int): Int = $anonfun.this.apply$mcII$sp(param); + def apply$mcII$sp(param: Int): Int = param + }; + (new anonymous class $anonfun(): Int => Int) + }; + 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/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._