Merge remote-tracking branch 'origin/2.10.x' into merge-2.10.x

* origin/2.10.x: (31 commits)
  Implicit vars should have non-implicit setters.
  Deprecate `scala.tools.nsc.Phases` because it's dead-code.
  scaladoc Template: remove duplicate code and several usages of Option.get.
  adds scala-reflect.jar to MIMA in ant
  Test showing the absence of a forward reference
  update mailmap
  Remove dead code from `Global`.
  Cleanup MemberLookup. Better explain ambiguous link targets.
  typedIdent no longer destroys attachments
  fixes incorrect handling of Annotated in lazy copier
  simplifies checkBounds
  Recurse into instantiations when stripping type vars.
  Extract base scaladoc functionality for the IDE.
  Expand pattern match position tests.
  SI-6288 Remedy ill-positioned extractor binding.
  SI-6288 Fix positioning of label jumps
  SI-6288 Position argument of unapply
  Fixes SI-6758: force LazyAnnnotationInfo for DefDef and TypeDef
  SI-6795 Simplify errors related to "abstract override" on type members
  SI-6795 Adds negative check for "abstract override" on types in traits
  ...

Conflicts:
	.mailmap
	src/compiler/scala/tools/nsc/Global.scala
	src/compiler/scala/tools/nsc/ast/DocComments.scala
	src/compiler/scala/tools/nsc/doc/base/CommentFactoryBase.scala
	src/compiler/scala/tools/nsc/doc/html/page/Source.scala
	src/compiler/scala/tools/nsc/doc/html/page/Template.scala
	src/compiler/scala/tools/nsc/doc/model/LinkTo.scala
	src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala
	src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala
	src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
	src/compiler/scala/tools/nsc/typechecker/Typers.scala
	src/reflect/scala/reflect/runtime/JavaMirrors.scala
	test/scaladoc/run/links.scala
This commit is contained in:
Paul Phillips 2012-12-20 12:58:03 -08:00
commit 106ca1b676
102 changed files with 1504 additions and 610 deletions

View File

@ -1,7 +1,27 @@
Aleksandar Prokopec <aleksandar@aleksandar-Latitude-E6500.(none)>
Aleksandar Prokopec <aleksandar@htpc.(none)>
Aleksandar Prokopec <aleksandar@htpc-axel22.(none)>
Aleksandar Prokopec <aleksandar@lampmac14.epfl.ch>
Aleksandar Prokopec <aleksandar.prokopec@epfl.ch>
Aleksandar Prokopec <aleksandar@aleksandar-Latitude-E6500.(none)>
Aleksandar Prokopec <aleksandar@htpc-axel22.(none)>
Aleksandar Prokopec <aleksandar@htpc.(none)>
Aleksandar Prokopec <aleksandar@lampmac14.epfl.ch>
Antonio Cunei <antonio.cunei@typesafe.com>
Caoyuan Deng <dcaoyuan@epfl.ch>
Chris Hodapp <clhodapp1@gmail.com>
Chris James <chrisJames@epfl.ch>
Christopher Vogt <vogt@epfl.ch>
Damien Obristi <damien.obrist@gmail.com>
Daniel C. Sobral <dcs@dcs-132-CK-NF79.(none)>
Daniel C. Sobral <dcs@dcs-132-CK-NF79.(none)>
Ilya Sergei <ilyas@epfl.ch>
Ingo Maier <ingoem@gmail.com>
Kenji Yoshida <6b656e6a69@gmail.com>
Luc Bourlier <skyluc@epfl.ch>
Martin Odersky <odersky@gamil.com>
Nada Amin <amin@epfl.ch>
Nada Amin <nada.amin@epfl.ch>
Natallie Baikevich <lu-a-jalla@ya.ru>
Pavel Pavlov <pavel.e.pavlov@gmail.com>
Pavel Pavlov <pavel.e.pavlov@gmail.com>
Philipp Haller <philipp.haller@typesafe.com>
Roland Kuhn <rk@rkuhn.info>
Rüdiger Klaehn <rklaehn@gmail.com>
Stéphane Micheloud <michelou@epfl.ch>

View File

@ -2503,6 +2503,7 @@ Binary compatibility testing
</artifact:dependencies>
<artifact:dependencies pathId="old.bc.classpath">
<dependency groupId="org.scala-lang" artifactId="scala-library" version="2.10.0-RC2"/>
<dependency groupId="org.scala-lang" artifactId="scala-reflect" version="2.10.0-RC2"/>
</artifact:dependencies>
</target>
@ -2518,7 +2519,19 @@ Binary compatibility testing
<classpath>
<path refid="mima.classpath"/>
</classpath>
</java>
</java>
<java
fork="true"
failonerror="true"
classname="com.typesafe.tools.mima.cli.Main">
<arg value="--prev"/>
<arg value="${org.scala-lang:scala-reflect:jar}"/>
<arg value="--curr"/>
<arg value="${build-pack.dir}/lib/scala-reflect.jar"/>
<classpath>
<path refid="mima.classpath"/>
</classpath>
</java>
</target>

View File

@ -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.
}
}
}

View File

@ -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)

View File

@ -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

View File

@ -16,11 +16,22 @@ import scala.collection.mutable
*/
trait DocComments { self: Global =>
var cookedDocComments = Map[Symbol, String]()
val cookedDocComments = mutable.HashMap[Symbol, String]()
/** The raw doc comment map */
val docComments = mutable.HashMap[Symbol, DocComment]()
def clearDocComments() {
cookedDocComments.clear()
docComments.clear()
defs.clear()
}
/** Associate comment with symbol `sym` at position `pos`. */
def docComment(sym: Symbol, docStr: String, pos: Position = NoPosition) =
if ((sym ne null) && (sym ne NoSymbol))
docComments += (sym -> DocComment(docStr, pos))
/** The raw doc comment of symbol `sym`, as it appears in the source text, "" if missing.
*/
def rawDocComment(sym: Symbol): String =
@ -47,25 +58,20 @@ trait DocComments { self: Global =>
* If a symbol does not have a doc comment but some overridden version of it does,
* the doc comment of the overridden version is copied instead.
*/
def cookedDocComment(sym: Symbol, docStr: String = ""): String = cookedDocComments.get(sym) match {
case Some(comment) =>
comment
case None =>
val ownComment = if (docStr.length == 0) docComments get sym map (_.template) getOrElse ""
def cookedDocComment(sym: Symbol, docStr: String = ""): String = cookedDocComments.getOrElseUpdate(sym, {
val ownComment = if (docStr.length == 0) docComments get sym map (_.template) getOrElse ""
else DocComment(docStr).template
val comment = superComment(sym) match {
case None =>
if (ownComment.indexOf("@inheritdoc") != -1)
reporter.warning(sym.pos, "The comment for " + sym +
" contains @inheritdoc, but no parent comment is available to inherit from.")
ownComment.replaceAllLiterally("@inheritdoc", "<invalid inheritdoc annotation>")
case Some(sc) =>
if (ownComment == "") sc
else expandInheritdoc(sc, merge(sc, ownComment, sym), sym)
}
cookedDocComments += (sym -> comment)
comment
}
superComment(sym) match {
case None =>
if (ownComment.indexOf("@inheritdoc") != -1)
reporter.warning(sym.pos, "The comment for " + sym +
" contains @inheritdoc, but no parent comment is available to inherit from.")
ownComment.replaceAllLiterally("@inheritdoc", "<invalid inheritdoc annotation>")
case Some(sc) =>
if (ownComment == "") sc
else expandInheritdoc(sc, merge(sc, ownComment, sym), sym)
}
})
/** The cooked doc comment of symbol `sym` after variable expansion, or "" if missing.
*

View File

@ -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 //////////////////////

View File

@ -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) =

View File

@ -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)
}
}

View File

@ -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

View File

@ -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", "")
}
}

View File

@ -5,7 +5,7 @@
package scala.tools.nsc
package doc
package model
package base
package comment
import scala.collection._

View File

@ -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
}

View File

@ -7,8 +7,9 @@ package scala.tools.nsc
package doc
package html
import base._
import base.comment._
import model._
import comment._
import scala.xml.NodeSeq
import scala.xml.dtd.{DocType, PublicID}
@ -126,12 +127,12 @@ abstract class HtmlPage extends Page { thisPage =>
}
def linkToHtml(text: Inline, link: LinkTo, hasLinks: Boolean) = link match {
case LinkToTpl(dtpl) =>
case LinkToTpl(dtpl: TemplateEntity) =>
if (hasLinks)
<a href={ relativeLinkTo(dtpl) } class="extype" name={ dtpl.qualifiedName }>{ inlineToHtml(text) }</a>
else
<span class="extype" name={ dtpl.qualifiedName }>{ inlineToHtml(text) }</span>
case LinkToMember(mbr, inTpl) =>
case LinkToMember(mbr: MemberEntity, inTpl: TemplateEntity) =>
if (hasLinks)
<a href={ relativeLinkTo(inTpl) + "#" + mbr.signature } class="extmbr" name={ mbr.qualifiedName }>{ inlineToHtml(text) }</a>
else
@ -140,7 +141,7 @@ abstract class HtmlPage extends Page { thisPage =>
<span class="extype" name={ tooltip }>{ inlineToHtml(text) }</span>
case LinkToExternal(name, url) =>
<a href={ url } class="extype" target="_top">{ inlineToHtml(text) }</a>
case NoLink =>
case _ =>
inlineToHtml(text)
}

View File

@ -8,6 +8,11 @@ package doc
package html
package page
import base._
import base.comment._
import model._
import model.diagram._
import scala.xml.{ NodeSeq, Text, UnprefixedAttribute }
import scala.language.postfixOps
@ -328,12 +333,10 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
}
def memberToShortCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = {
if (mbr.comment.isEmpty)
NodeSeq.Empty
else
<p class="shortcomment cmt">{ memberToUseCaseCommentHtml(mbr, isSelf) }{ inlineToHtml(mbr.comment.get.short) }</p>
}
def memberToShortCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq =
mbr.comment.fold(NodeSeq.Empty) { comment =>
<p class="shortcomment cmt">{ memberToUseCaseCommentHtml(mbr, isSelf) }{ inlineToHtml(comment.short) }</p>
}
def memberToInlineCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq =
<p class="comment cmt">{ inlineToHtml(mbr.comment.get.short) }</p>
@ -354,37 +357,34 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
case _ => Nil
}
def mbrCmt = mbr.comment.get
def paramCommentToHtml(prs: List[ParameterEntity]): NodeSeq = prs match {
def paramCommentToHtml(prs: List[ParameterEntity], comment: Comment): NodeSeq = prs match {
case (tp: TypeParam) :: rest =>
val paramEntry: NodeSeq = {
<dt class="tparam">{ tp.name }</dt><dd class="cmt">{ bodyToHtml(mbrCmt.typeParams(tp.name)) }</dd>
<dt class="tparam">{ tp.name }</dt><dd class="cmt">{ bodyToHtml(comment.typeParams(tp.name)) }</dd>
}
paramEntry ++ paramCommentToHtml(rest)
paramEntry ++ paramCommentToHtml(rest, comment)
case (vp: ValueParam) :: rest =>
val paramEntry: NodeSeq = {
<dt class="param">{ vp.name }</dt><dd class="cmt">{ bodyToHtml(mbrCmt.valueParams(vp.name)) }</dd>
<dt class="param">{ vp.name }</dt><dd class="cmt">{ bodyToHtml(comment.valueParams(vp.name)) }</dd>
}
paramEntry ++ paramCommentToHtml(rest)
paramEntry ++ paramCommentToHtml(rest, comment)
case _ =>
NodeSeq.Empty
}
if (mbr.comment.isEmpty) NodeSeq.Empty
else {
mbr.comment.fold(NodeSeq.Empty) { comment =>
val cmtedPrs = prs filter {
case tp: TypeParam => mbrCmt.typeParams isDefinedAt tp.name
case vp: ValueParam => mbrCmt.valueParams isDefinedAt vp.name
case tp: TypeParam => comment.typeParams isDefinedAt tp.name
case vp: ValueParam => comment.valueParams isDefinedAt vp.name
}
if (cmtedPrs.isEmpty && mbrCmt.result.isEmpty) NodeSeq.Empty
if (cmtedPrs.isEmpty && comment.result.isEmpty) NodeSeq.Empty
else {
<dl class="paramcmts block">{
paramCommentToHtml(cmtedPrs) ++ (
mbrCmt.result match {
paramCommentToHtml(cmtedPrs, comment) ++ (
comment.result match {
case None => NodeSeq.Empty
case Some(cmt) =>
<dt>returns</dt><dd class="cmt">{ bodyToHtml(cmt) }</dd>
@ -463,7 +463,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
// --- start attributes block vals
val attributes: Seq[scala.xml.Node] = {
val attributes: NodeSeq = {
val fvs: List[comment.Paragraph] = visibility(mbr).toList
if (fvs.isEmpty || isReduced) NodeSeq.Empty
else {
@ -472,7 +472,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
}
val definitionClasses: Seq[scala.xml.Node] = {
val definitionClasses: NodeSeq = {
val inDefTpls = mbr.inDefinitionTemplates
if ((inDefTpls.tail.isEmpty && (inDefTpls.head == inTpl)) || isReduced) NodeSeq.Empty
else {
@ -481,7 +481,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
}
val fullSignature: Seq[scala.xml.Node] = {
val fullSignature: NodeSeq = {
mbr match {
case nte: NonTemplateMemberEntity if nte.isUseCase =>
<div class="full-signature-block toggleContainer">
@ -492,14 +492,14 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
}
val selfType: Seq[scala.xml.Node] = mbr match {
val selfType: NodeSeq = mbr match {
case dtpl: DocTemplateEntity if (isSelf && !dtpl.selfType.isEmpty && !isReduced) =>
<dt>Self Type</dt>
<dd>{ typeToHtml(dtpl.selfType.get, hasLinks = true) }</dd>
case _ => NodeSeq.Empty
}
val annotations: Seq[scala.xml.Node] = {
val annotations: NodeSeq = {
// A list of annotations which don't show their arguments, e. g. because they are shown separately.
val annotationsWithHiddenArguments = List("deprecated", "Deprecated", "migration")
@ -521,7 +521,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
} else NodeSeq.Empty
}
val sourceLink: Seq[scala.xml.Node] = mbr match {
val sourceLink: NodeSeq = mbr match {
case dtpl: DocTemplateEntity if (isSelf && dtpl.sourceUrl.isDefined && dtpl.inSource.isDefined && !isReduced) =>
val (absFile, _) = dtpl.inSource.get
<dt>Source</dt>
@ -529,83 +529,87 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
case _ => NodeSeq.Empty
}
val deprecation: Seq[scala.xml.Node] =
if (mbr.deprecation.isEmpty || isReduced) NodeSeq.Empty
else {
<dt>Deprecated</dt>
<dd class="cmt">{ bodyToHtml(mbr.deprecation.get) }</dd>
val deprecation: NodeSeq =
mbr.deprecation match {
case Some(deprecation) if !isReduced =>
<dt>Deprecated</dt>
<dd class="cmt">{ bodyToHtml(deprecation) }</dd>
case _ => NodeSeq.Empty
}
val migration: Seq[scala.xml.Node] =
if(mbr.migration.isEmpty || isReduced) NodeSeq.Empty
else {
val migration: NodeSeq =
mbr.migration match {
case Some(migration) if !isReduced =>
<dt>Migration</dt>
<dd class="cmt">{ bodyToHtml(mbr.migration.get) }</dd>
<dd class="cmt">{ bodyToHtml(migration) }</dd>
case _ => NodeSeq.Empty
}
val mainComment: Seq[scala.xml.Node] = mbr.comment match {
val mainComment: NodeSeq = mbr.comment match {
case Some(comment) if (! isReduced) =>
def orEmpty[T](it: Iterable[T])(gen: =>NodeSeq): NodeSeq =
if (it.isEmpty) NodeSeq.Empty else gen
val example =
if(!comment.example.isEmpty)
orEmpty(comment.example) {
<div class="block">Example{ if (comment.example.length > 1) "s" else ""}:
<ol>{
val exampleXml: List[scala.xml.NodeSeq] =
for(example <- comment.example ) yield
<li class="cmt">{ bodyToHtml(example) }</li>
exampleXml.reduceLeft(_ ++ Text(", ") ++ _)
<ol>{
val exampleXml: List[NodeSeq] = for (ex <- comment.example) yield
<li class="cmt">{ bodyToHtml(ex) }</li>
exampleXml.reduceLeft(_ ++ Text(", ") ++ _)
}</ol>
</div>
else NodeSeq.Empty
</div>
}
val version: Seq[scala.xml.Node] =
if(!comment.version.isEmpty) {
val version: NodeSeq =
orEmpty(comment.version) {
<dt>Version</dt>
<dd>{ for(body <- comment.version.toList) yield {bodyToHtml(body)} }</dd>
} else NodeSeq.Empty
<dd>{ for(body <- comment.version.toList) yield bodyToHtml(body) }</dd>
}
val sinceVersion: Seq[scala.xml.Node] =
if(!comment.since.isEmpty) {
val sinceVersion: NodeSeq =
orEmpty(comment.since) {
<dt>Since</dt>
<dd>{ for(body <- comment.since.toList) yield {bodyToHtml(body)} }</dd>
} else NodeSeq.Empty
<dd>{ for(body <- comment.since.toList) yield bodyToHtml(body) }</dd>
}
val note: Seq[scala.xml.Node] =
if(!comment.note.isEmpty) {
val note: NodeSeq =
orEmpty(comment.note) {
<dt>Note</dt>
<dd>{
val noteXml: List[scala.xml.NodeSeq] = (for(note <- comment.note ) yield <span class="cmt">{bodyToHtml(note)}</span> )
val noteXml: List[NodeSeq] = for(note <- comment.note ) yield <span class="cmt">{bodyToHtml(note)}</span>
noteXml.reduceLeft(_ ++ Text(", ") ++ _)
}</dd>
} else NodeSeq.Empty
}
val seeAlso: Seq[scala.xml.Node] =
if(!comment.see.isEmpty) {
val seeAlso: NodeSeq =
orEmpty(comment.see) {
<dt>See also</dt>
<dd>{
val seeXml:List[scala.xml.NodeSeq]=(for(see <- comment.see ) yield <span class="cmt">{bodyToHtml(see)}</span> )
val seeXml: List[NodeSeq] = for(see <- comment.see ) yield <span class="cmt">{bodyToHtml(see)}</span>
seeXml.reduceLeft(_ ++ _)
}</dd>
} else NodeSeq.Empty
}
val exceptions: Seq[scala.xml.Node] =
if(!comment.throws.isEmpty) {
val exceptions: NodeSeq =
orEmpty(comment.throws) {
<dt>Exceptions thrown</dt>
<dd>{
val exceptionsXml: Iterable[scala.xml.NodeSeq] =
for(exception <- comment.throws.toList.sortBy(_._1) ) yield
<span class="cmt">{Text(exception._1) ++ bodyToHtml(exception._2)}</span>
val exceptionsXml: List[NodeSeq] =
for((name, body) <- comment.throws.toList.sortBy(_._1) ) yield
<span class="cmt">{Text(name) ++ bodyToHtml(body)}</span>
exceptionsXml.reduceLeft(_ ++ Text("") ++ _)
}</dd>
} else NodeSeq.Empty
}
val todo: Seq[scala.xml.Node] =
if(!comment.todo.isEmpty) {
val todo: NodeSeq =
orEmpty(comment.todo) {
<dt>To do</dt>
<dd>{
val todoXml: List[scala.xml.NodeSeq] = (for(todo <- comment.todo ) yield <span class="cmt">{bodyToHtml(todo)}</span> )
val todoXml: List[NodeSeq] = (for(todo <- comment.todo ) yield <span class="cmt">{bodyToHtml(todo)}</span> )
todoXml.reduceLeft(_ ++ Text(", ") ++ _)
}</dd>
} else NodeSeq.Empty
}
example ++ version ++ sinceVersion ++ exceptions ++ todo ++ note ++ seeAlso

View File

@ -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

View File

@ -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))
}
}

View File

@ -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

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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", "")
}
}

View File

@ -10,8 +10,6 @@ package scala.tools.nsc
package doc
package model
import comment._
import scala.collection._
import symtab.Flags

View File

@ -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 {

View File

@ -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

View File

@ -3,7 +3,6 @@ package model
package diagram
import model._
import comment.CommentFactory
import java.util.regex.{Pattern, Matcher}
import scala.util.matching.Regex

View File

@ -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] = {

View File

@ -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))
}
}
}
}
}

View File

@ -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.
*/

View File

@ -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
}

View File

@ -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

View File

@ -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)

View File

@ -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"

View File

@ -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 =>

View File

@ -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 {

View File

@ -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)

View File

@ -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 {

View File

@ -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

View File

@ -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
}

View File

@ -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))

View File

@ -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))
}

View File

@ -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

View File

@ -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:
*

View File

@ -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

View File

@ -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 }

View File

@ -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 {

View File

@ -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

View File

@ -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
}
/**

View File

@ -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

View File

@ -1 +1 @@
c5788c5e518eb267445c5a995fd98b2210f90a58 ?javac-artifacts.jar
61931a51bb1a2d308d214b96d06e9a8808515dcf ?javac-artifacts.jar

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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("")
}

View File

@ -1,11 +1,6 @@
t4044.scala:9: error: AnyRef takes no type parameters, expected: one
M[AnyRef] // error, (AnyRef :: *) not kind-conformant to (N :: * -> * -> *)
^
t4044.scala:9: error: kinds of the type arguments (<error>) do not conform to the expected kinds of the type parameters (type N).
<error>'s type parameters do not match type N's expected parameters:
<none> has no type parameters, but type N has one
M[AnyRef] // error, (AnyRef :: *) not kind-conformant to (N :: * -> * -> *)
^
t4044.scala:11: error: kinds of the type arguments (Test.A) do not conform to the expected kinds of the type parameters (type N).
Test.A's type parameters do not match type N's expected parameters:
type _ has no type parameters, but type O has one
@ -16,4 +11,4 @@ Test.C's type parameters do not match type N's expected parameters:
type _ has one type parameter, but type _ has none
M[C] // error, (C :: (* -> * -> * -> *) not kind-conformant to (N :: * -> * -> *)
^
four errors found
three errors found

View File

@ -0,0 +1,4 @@
t5361.scala:2: error: only declarations allowed here
val x : { val self = this } = new { self => }
^
one error found

View File

@ -0,0 +1,3 @@
class A {
val x : { val self = this } = new { self => }
}

View File

@ -0,0 +1,4 @@
t5390.scala:7: error: forward reference extends over definition of value b
val b = a.B("")
^
one error found

View File

@ -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
}
}

View File

@ -0,0 +1,4 @@
t5390b.scala:7: error: forward reference extends over definition of value b
val b = a.B("")
^
one error found

View File

@ -0,0 +1,10 @@
class A {
case class B(s: String)
}
object X {
def foo {
val b = a.B("")
val a = new A
}
}

View File

@ -0,0 +1,4 @@
t5390c.scala:7: error: forward reference extends over definition of value b
val b = new a.B("")
^
one error found

View File

@ -0,0 +1,10 @@
class A {
case class B(s: String)
}
object X {
def foo {
val b = new a.B("")
val a = new A
}
}

View File

@ -0,0 +1,4 @@
t5390d.scala:7: error: forward reference extends over definition of value b
val b = a.B.toString
^
one error found

View File

@ -0,0 +1,10 @@
class A {
case class B(s: String)
}
object X {
def foo {
val b = a.B.toString
val a = new A
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
)
}

View File

@ -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

View File

@ -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 }

View File

View File

@ -0,0 +1 @@
-language:experimental.macros

View File

@ -0,0 +1,53 @@
import scala.language.experimental.macros
import scala.reflect.macros.Context
import collection.mutable.ListBuffer
import collection.mutable.Stack
object Macros {
trait TypedFunction {
def tree: scala.reflect.runtime.universe.Tree
val typeIn: String
val typeOut: String
}
def tree[T,U](f:Function1[T,U]): Function1[T,U] = macro tree_impl[T,U]
def tree_impl[T:c.WeakTypeTag,U:c.WeakTypeTag](c: Context)
(f:c.Expr[Function1[T,U]]): c.Expr[Function1[T,U]] = {
import c.universe._
val ttag = c.weakTypeTag[U]
f match {
case Expr(Function(List(ValDef(_,n,tp,_)),b)) =>
// normalize argument name
var b1 = new Transformer {
override def transform(tree: Tree): Tree = tree match {
case Ident(x) if (x==n) => Ident(newTermName("_arg"))
case tt @ TypeTree() if tt.original != null => TypeTree(tt.tpe) setOriginal transform(tt.original)
// without the fix to LazyTreeCopier.Annotated, we would need to uncomment the line below to make the macro work
// that's because the pattern match in the input expression gets expanded into Typed(<x>, TypeTree(<Int @unchecked>))
// with the original of the TypeTree being Annotated(<@unchecked>, Ident(<x>))
// then the macro tries to replace all Ident(<x>) trees with Ident(<_arg>), recurs into the original of the TypeTree, changes it,
// but leaves the <@unchecked> part untouched. this signals the misguided LazyTreeCopier that the Annotated tree hasn't been modified,
// so the original tree should be copied over and returned => crash when later <x: @unchecked> re-emerges from TypeTree.original
// case Annotated(annot, arg) => treeCopy.Annotated(tree, transform(annot).duplicate, transform(arg))
case _ => super.transform(tree)
}
}.transform(b)
val reifiedTree = c.reifyTree(treeBuild.mkRuntimeUniverseRef, EmptyTree, b1)
val reifiedExpr = c.Expr[scala.reflect.runtime.universe.Expr[T => U]](reifiedTree)
val template =
c.universe.reify(new (T => U) with TypedFunction {
override def toString = c.literal(tp+" => "+ttag.tpe+" { "+b1.toString+" } ").splice // DEBUG
def tree = reifiedExpr.splice.tree
val typeIn = c.literal(tp.toString).splice
val typeOut = c.literal(ttag.tpe.toString).splice
def apply(_arg: T): U = c.Expr[U](b1)(ttag.asInstanceOf[c.WeakTypeTag[U]]).splice
})
val untyped = c.resetLocalAttrs(template.tree)
c.Expr[T => U](untyped)
case _ => sys.error("Bad function type")
}
}
}

View File

@ -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) } }
}

View File

@ -0,0 +1 @@
-language:experimental.macros

View File

@ -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
}

View File

@ -0,0 +1,4 @@
object Test extends App {
def bar = 2
Macros.foo
}

View File

@ -0,0 +1 @@
-feature -Xfatal-warnings

View File

@ -0,0 +1,3 @@
object O {
implicit var x: Int = 0
}

View File

@ -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
}

View File

@ -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 = ""
}
}

View File

@ -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)))))))

View File

@ -0,0 +1,71 @@
import scala.tools.nsc.doc
import scala.tools.nsc.doc.base.LinkTo
import scala.tools.nsc.doc.base.comment._
import scala.tools.nsc.interactive._
import scala.tools.nsc.interactive.tests._
import scala.tools.nsc.util._
import scala.tools.nsc.io._
object Test extends InteractiveTest {
override val settings: doc.Settings = docSettings
val tags = Seq(
"@example `\"abb\".permutations = Iterator(abb, bab, bba)`",
"@version 1.0, 09/07/2012",
"@since 2.10",
"@todo this method is unsafe",
"@note Don't inherit!",
"@see some other method"
)
val comment = "This is a test comment."
val caret = "<caret>"
def text(nTags: Int) =
"""|/** %s
|
| * %s */
|trait Commented {}
|class User(c: %sCommented)""".stripMargin.format(comment, tags take nTags mkString "\n", caret)
override def main(args: Array[String]) {
val documenter = new Doc(settings) {
val global: compiler.type = compiler
def chooseLink(links: List[LinkTo]): LinkTo = links.head
}
for (i <- 1 to tags.length) {
val markedText = text(i)
val idx = markedText.indexOf(caret)
val fileText = markedText.substring(0, idx) + markedText.substring(idx + caret.length)
val source = sourceFiles(0)
val batch = new BatchSourceFile(source.file, fileText.toCharArray)
val reloadResponse = new Response[Unit]
compiler.askReload(List(batch), reloadResponse)
reloadResponse.get.left.toOption match {
case None =>
reporter.println("Couldn't reload")
case Some(_) =>
val treeResponse = new compiler.Response[compiler.Tree]
val pos = compiler.rangePos(batch, idx, idx, idx)
compiler.askTypeAt(pos, treeResponse)
treeResponse.get.left.toOption match {
case Some(tree) =>
val sym = tree.tpe.typeSymbol
documenter.retrieve(sym, sym.owner) match {
case Some(HtmlResult(comment)) =>
import comment._
val tags: List[(String, Iterable[Body])] =
List(("@example", example), ("@version", version), ("@since", since.toList), ("@todo", todo), ("@note", note), ("@see", see))
val str = ("body:" + body + "\n") +
tags.map{ case (name, bodies) => name + ":" + bodies.mkString("\n") }.mkString("\n")
reporter.println(str)
case Some(_) => reporter.println("Got unexpected result")
case None => reporter.println("Got no result")
}
case None => reporter.println("Couldn't find a typedTree")
}
}
}
}
}

View File

@ -0,0 +1 @@
object Test

View File

@ -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()
}
}
}

View File

@ -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]
---

View File

@ -0,0 +1,85 @@
[[syntax trees at end of patmat]] // newSource1
[7]package [7]<empty> {
[7]object Case3 extends [13][106]scala.AnyRef {
[106]def <init>(): [13]Case3.type = [106]{
[106][106][106]Case3.super.<init>();
[13]()
};
[21]def unapply([29]z: [32]<type: [32]scala.Any>): [21]Option[Int] = [56][52][52]scala.Some.apply[[52]Int]([58]-1);
[64]{
[64]case <synthetic> val x1: [64]Any = [64]"";
[64]case5()[84]{
[84]<synthetic> val o7: [84]Option[Int] = [84][84]Case3.unapply([84]x1);
[84]if ([84]o7.isEmpty.unary_!)
[84]{
[90]val nr: [90]Int = [90]o7.get;
[97][97]matchEnd4([97]())
}
else
[84][84]case6()
};
[64]case6(){
[64][64]matchEnd4([64]throw [64][64][64]new [64]MatchError([64]x1))
};
[64]matchEnd4(x: [NoPosition]Unit){
[64]x
}
}
};
[113]object Case4 extends [119][217]scala.AnyRef {
[217]def <init>(): [119]Case4.type = [217]{
[217][217][217]Case4.super.<init>();
[119]()
};
[127]def unapplySeq([138]z: [141]<type: [141]scala.Any>): [127]Option[List[Int]] = [167]scala.None;
[175]{
[175]case <synthetic> val x1: [175]Any = [175]"";
[175]case5()[195]{
[195]<synthetic> val o7: [195]Option[List[Int]] = [195][195]Case4.unapplySeq([195]x1);
[195]if ([195]o7.isEmpty.unary_!)
[195]if ([195][195][195][195]o7.get.!=([195]null).&&([195][195][195][195]o7.get.lengthCompare([195]1).==([195]0)))
[195]{
[201]val nr: [201]Int = [201][201]o7.get.apply([201]0);
[208][208]matchEnd4([208]())
}
else
[195][195]case6()
else
[195][195]case6()
};
[175]case6(){
[175][175]matchEnd4([175]throw [175][175][175]new [175]MatchError([175]x1))
};
[175]matchEnd4(x: [NoPosition]Unit){
[175]x
}
}
};
[224]object Case5 extends [230][312]scala.AnyRef {
[312]def <init>(): [230]Case5.type = [312]{
[312][312][312]Case5.super.<init>();
[230]()
};
[238]def unapply([246]z: [249]<type: [249]scala.Any>): [238]Boolean = [265]true;
[273]{
[273]case <synthetic> val x1: [273]Any = [273]"";
[273]case5()[293]{
[293]<synthetic> val o7: [293]Option[List[Int]] = [293][293]Case4.unapplySeq([293]x1);
[293]if ([293]o7.isEmpty.unary_!)
[293]if ([293][293][293][293]o7.get.!=([293]null).&&([293][293][293][293]o7.get.lengthCompare([293]0).==([293]0)))
[304][304]matchEnd4([304]())
else
[293][293]case6()
else
[293][293]case6()
};
[273]case6(){
[273][273]matchEnd4([273]throw [273][273][273]new [273]MatchError([273]x1))
};
[273]matchEnd4(x: [NoPosition]Unit){
[273]x
}
}
}
}

View File

@ -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()
}
}
}

View File

@ -0,0 +1,80 @@
object Case3 extends Object {
// fields:
// methods
def unapply(z: Object (REF(class Object))): Option {
locals: value z
startBlock: 1
blocks: [1]
1:
2 NEW REF(class Some)
2 DUP(REF(class Some))
2 CONSTANT(-1)
2 BOX INT
2 CALL_METHOD scala.Some.<init> (static-instance)
2 RETURN(REF(class Option))
}
Exception handlers:
def main(args: Array[String] (ARRAY[REF(class String)])): Unit {
locals: value args, value x1, value x2, value x
startBlock: 1
blocks: [1,2,3,6,7]
1:
4 CONSTANT("")
4 STORE_LOCAL(value x1)
4 SCOPE_ENTER value x1
4 JUMP 2
2:
5 LOAD_LOCAL(value x1)
5 IS_INSTANCE REF(class String)
5 CZJUMP (BOOL)NE ? 3 : 6
3:
5 LOAD_LOCAL(value x1)
5 CHECK_CAST REF(class String)
5 STORE_LOCAL(value x2)
5 SCOPE_ENTER value x2
6 LOAD_MODULE object Predef
6 CONSTANT("case 0")
6 CALL_METHOD scala.Predef.println (dynamic)
6 LOAD_FIELD scala.runtime.BoxedUnit.UNIT
6 STORE_LOCAL(value x)
6 JUMP 7
6:
8 LOAD_MODULE object Predef
8 CONSTANT("default")
8 CALL_METHOD scala.Predef.println (dynamic)
8 LOAD_FIELD scala.runtime.BoxedUnit.UNIT
8 STORE_LOCAL(value x)
8 JUMP 7
7:
10 LOAD_MODULE object Predef
10 CONSTANT("done")
10 CALL_METHOD scala.Predef.println (dynamic)
10 RETURN(UNIT)
}
Exception handlers:
def <init>(): Case3.type {
locals:
startBlock: 1
blocks: [1]
1:
12 THIS(Case3)
12 CALL_METHOD java.lang.Object.<init> (super())
12 RETURN(UNIT)
}
Exception handlers:
}

View File

@ -0,0 +1,22 @@
import scala.tools.partest.IcodeTest
object Test extends IcodeTest {
override def code =
"""object Case3 { // 01
| def unapply(z: Any): Option[Int] = Some(-1) // 02
| def main(args: Array[String]) { // 03
| ("": Any) match { // 04
| case x : String => // 05 Read: <linenumber> JUMP <target basic block id>
| println("case 0") // 06 expecting "6 JUMP 7", was "8 JUMP 7"
| case _ => // 07
| println("default") // 08 expecting "8 JUMP 7"
| } // 09
| println("done") // 10
| }
|}""".stripMargin
override def show() {
val lines1 = collectIcode("")
println(lines1 mkString "\n")
}
}

View File

@ -0,0 +1,2 @@
false
List(JavaAnnotationWithNestedEnum(value = VALUE))

View File

@ -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)
}

View File

@ -0,0 +1,22 @@
[[syntax trees at end of specialize]] // newSource1
package <empty> {
class Foo extends Object {
def <init>(): Foo = {
Foo.super.<init>();
()
};
private[this] val f: Int => Int = {
@SerialVersionUID(0) final <synthetic> class $anonfun extends scala.runtime.AbstractFunction1$mcII$sp with Serializable {
def <init>(): anonymous class $anonfun = {
$anonfun.super.<init>();
()
};
final def apply(param: Int): Int = $anonfun.this.apply$mcII$sp(param);
<specialized> def apply$mcII$sp(param: Int): Int = param
};
(new anonymous class $anonfun(): Int => Int)
};
<stable> <accessor> def f(): Int => Int = Foo.this.f
}
}

View File

@ -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()
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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]")
}
}
}

View File

@ -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)
}
}
}

Some files were not shown because too many files have changed in this diff Show More