diff options
Diffstat (limited to 'src/compiler')
13 files changed, 191 insertions, 59 deletions
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 2ba45c5972..f4039cf6d3 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -1872,7 +1872,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => def unpackLocation: AnyRef = null /** Remove private modifier from symbol `sym`s definition. If `sym` is a - * term symbol rename it by expanding its name to avoid name clashes + * is not a constructor nor a static module rename it by expanding its name to avoid name clashes + * @param base the fully qualified name of this class will be appended if name expansion is needed */ final def makeNotPrivate(base: Symbol) { if (this.isPrivate) { diff --git a/src/compiler/scala/reflect/runtime/Universe.scala b/src/compiler/scala/reflect/runtime/Universe.scala index 324fee87ab..7a5dda3d8e 100644 --- a/src/compiler/scala/reflect/runtime/Universe.scala +++ b/src/compiler/scala/reflect/runtime/Universe.scala @@ -39,6 +39,11 @@ class Universe extends SymbolTable { definitions.AnyValClass // force it. + type TreeAnnotation = Position + val NoTreeAnnotation: TreeAnnotation = NoPosition + def positionToAnnotation(pos: Position): TreeAnnotation = pos // TODO + def annotationToPosition(annot: TreeAnnotation): Position = annot //TODO + // establish root association to avoid cyclic dependency errors later classToScala(classOf[java.lang.Object]).initialize diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala index 678f7b3028..d3f4688d4b 100755 --- a/src/compiler/scala/tools/nsc/ast/DocComments.scala +++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala @@ -229,31 +229,36 @@ trait DocComments { self: Global => * 1. It takes longer to run compared to merge * 2. The inheritdoc annotation should not be used very often, as building the comment from pieces severely * impacts performance + * + * @param parent The source (or parent) comment + * @param child The child (overriding member or usecase) comment + * @param sym The child symbol + * @return The child comment with the inheritdoc sections expanded */ - def expandInheritdoc(src: String, dst: String, sym: Symbol): String = - if (dst.indexOf("@inheritdoc") == -1) - dst + def expandInheritdoc(parent: String, child: String, sym: Symbol): String = + if (child.indexOf("@inheritdoc") == -1) + child else { - val srcSections = tagIndex(src) - val dstSections = tagIndex(dst) - val srcTagMap = sectionTagMap(src, srcSections) - val srcNamedParams = Map() + - ("@param" -> paramDocs(src, "@param", srcSections)) + - ("@tparam" -> paramDocs(src, "@tparam", srcSections)) + - ("@throws" -> paramDocs(src, "@throws", srcSections)) + val parentSections = tagIndex(parent) + val childSections = tagIndex(child) + val parentTagMap = sectionTagMap(parent, parentSections) + val parentNamedParams = Map() + + ("@param" -> paramDocs(parent, "@param", parentSections)) + + ("@tparam" -> paramDocs(parent, "@tparam", parentSections)) + + ("@throws" -> paramDocs(parent, "@throws", parentSections)) val out = new StringBuilder - def replaceInheritdoc(src: String, dst: String) = - if (dst.indexOf("@inheritdoc") == -1) - dst - else - dst.replaceAllLiterally("@inheritdoc", src) + def replaceInheritdoc(childSection: String, parentSection: => String) = + if (childSection.indexOf("@inheritdoc") == -1) + childSection + else + childSection.replaceAllLiterally("@inheritdoc", parentSection) - def getSourceSection(section: (Int, Int)): String = { + def getParentSection(section: (Int, Int)): String = { - def getSectionHeader = extractSectionTag(dst, section) match { - case param@("@param"|"@tparam"|"@throws") => param + " " + extractSectionParam(dst, section) + def getSectionHeader = extractSectionTag(child, section) match { + case param@("@param"|"@tparam"|"@throws") => param + " " + extractSectionParam(child, section) case other => other } @@ -261,17 +266,19 @@ trait DocComments { self: Global => paramMap.get(param) match { case Some(section) => // Cleanup the section tag and parameter - val sectionTextBounds = extractSectionText(src, section) - cleanupSectionText(src.substring(sectionTextBounds._1, sectionTextBounds._2)) + val sectionTextBounds = extractSectionText(parent, section) + cleanupSectionText(parent.substring(sectionTextBounds._1, sectionTextBounds._2)) case None => reporter.info(sym.pos, "The \"" + getSectionHeader + "\" annotation of the " + sym + " comment contains @inheritdoc, but the corresponding section in the parent is not defined.", true) "<invalid inheritdoc annotation>" } - dst.substring(section._1, section._1 + 7) match { - case param@("@param "|"@tparam"|"@throws") => sectionString(extractSectionParam(dst, section), srcNamedParams(param.trim)) - case _ => sectionString(extractSectionTag(dst, section), srcTagMap) + child.substring(section._1, section._1 + 7) match { + case param@("@param "|"@tparam"|"@throws") => + sectionString(extractSectionParam(child, section), parentNamedParams(param.trim)) + case _ => + sectionString(extractSectionTag(child, section), parentTagMap) } } @@ -283,11 +290,11 @@ trait DocComments { self: Global => // Append main comment out.append("/**") - out.append(replaceInheritdoc(mainComment(src, srcSections), mainComment(dst, dstSections))) + out.append(replaceInheritdoc(mainComment(child, childSections), mainComment(parent, parentSections))) // Append sections - for (section <- dstSections) - out.append(replaceInheritdoc(getSourceSection(section), dst.substring(section._1, section._2))) + for (section <- childSections) + out.append(replaceInheritdoc(child.substring(section._1, section._2), getParentSection(section))) out.append("*/") out.toString diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala index bd5f98bab7..0c9c88c0f5 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -345,6 +345,17 @@ class Template(universe: doc.Universe, tpl: DocTemplateEntity) extends HtmlPage } } + val fullSignature: Seq[scala.xml.Node] = { + mbr match { + case nte: NonTemplateMemberEntity if nte.isUseCase => + <div class="full-signature-block toggleContainer"> + <span class="toggle">Full Signature</span> + <div class="hiddenContent full-signature-usecase">{ signature(nte.useCaseOf.get,true) }</div> + </div> + case _ => NodeSeq.Empty + } + } + val selfType: Seq[scala.xml.Node] = mbr match { case dtpl: DocTemplateEntity if (isSelf && !dtpl.selfType.isEmpty && !isReduced) => <dt>Self Type</dt> @@ -466,7 +477,7 @@ class Template(universe: doc.Universe, tpl: DocTemplateEntity) extends HtmlPage } // end attributes block vals --- - val attributesInfo = attributes ++ definitionClasses ++ selfType ++ annotations ++ deprecation ++ migration ++ sourceLink ++ mainComment + val attributesInfo = attributes ++ definitionClasses ++ fullSignature ++ selfType ++ annotations ++ deprecation ++ migration ++ sourceLink ++ mainComment val attributesBlock = if (attributesInfo.isEmpty) NodeSeq.Empty diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css index 4f552b7169..6fb83c133e 100644 --- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css @@ -340,6 +340,30 @@ div.members > ol > li:last-child { color: darkgreen; } +.full-signature-usecase h4 span { + font-size: 10pt; +} + +.full-signature-usecase > #signature { + padding-top: 0px; +} + +#template .full-signature-usecase > .signature.closed { + background: none; +} + +#template .full-signature-usecase > .signature.opened { + background: none; +} + +.full-signature-block { + padding: 5px 0 0; + border-top: 1px solid #EBEBEB; + margin-top: 5px; + margin-bottom: 5px; +} + + /* Comments text formating */ .cmt {} diff --git a/src/compiler/scala/tools/nsc/symtab/Positions.scala b/src/compiler/scala/tools/nsc/symtab/Positions.scala index c96c709fb0..680b06f8ce 100644 --- a/src/compiler/scala/tools/nsc/symtab/Positions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Positions.scala @@ -14,6 +14,15 @@ self: scala.tools.nsc.symtab.SymbolTable => type Position = scala.tools.nsc.util.Position val NoPosition = scala.tools.nsc.util.NoPosition + type TreeAnnotation = scala.tools.nsc.util.TreeAnnotation + val NoTreeAnnotation: TreeAnnotation = NoPosition + def positionToAnnotation(pos: Position): TreeAnnotation = pos + def annotationToPosition(annot: TreeAnnotation): Position = annot.pos + override def _checkSetAnnotation(tree: Tree, annot: TreeAnnotation): Unit = { + if (tree.pos != NoPosition && tree.pos != annot.pos) debugwarn("Overwriting annotation "+ tree.annotation +" of tree "+ tree +" with annotation "+ annot) + // if ((tree.annotation.isInstanceOf[scala.tools.nsc.util.Position] || !annot.isInstanceOf[scala.tools.nsc.util.Position]) && tree.isInstanceOf[Block]) + // println("Updating block from "+ tree.annotation +" to "+ annot) + } def focusPos(pos: Position): Position = pos.focus def isRangePos(pos: Position): Boolean = pos.isRange def showPos(pos: Position): String = pos.show diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 4c3972519a..5104518dd9 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -28,6 +28,9 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { /** the following two members override abstract members in Transform */ val phaseName: String = "extmethods" + /** The following flags may be set by this phase: */ + override def phaseNewFlags: Long = notPRIVATE + def newTransformer(unit: CompilationUnit): Transformer = new Extender(unit) @@ -101,6 +104,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { case Template(_, _, _) => if (currentOwner.isDerivedValueClass) { extensionDefs(currentOwner.companionModule) = new mutable.ListBuffer[Tree] + currentOwner.primaryConstructor.makeNotPrivate(NoSymbol) super.transform(tree) } else if (currentOwner.isStaticOwner) { super.transform(tree) diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index f32ad9293c..5287fad3bb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -169,6 +169,16 @@ trait MethodSynthesis { self: Namer => import NamerErrorGen._ + + /** TODO - synthesize method. + */ + def enterImplicitClass(tree: ClassDef) { + /** e.g. + val ClassDef(mods, name, tparams, impl) = tree + val converter = ImplicitClassConverter(tree).createAndEnterSymbol() + ... + */ + } def enterGetterSetter(tree: ValDef) { val ValDef(mods, name, _, _) = tree @@ -230,14 +240,33 @@ trait MethodSynthesis { } trait Derived { + /** The tree from which we are deriving a synthetic member. */ + def tree: Tree def name: TermName def flagsMask: Long def flagsExtra: Long + + /** The tree, symbol, and type completer for the synthetic member. */ def completer(sym: Symbol): Type + def derivedSym: Symbol + def derivedTree: Tree } - trait DerivedFromValDef extends Derived { - /** The declaration from which we are deriving. - */ + + trait DerivedFromMemberDef extends Derived { + def tree: MemberDef + + // Final methods to make the rest easier to reason about. + final def mods = tree.mods + final def basisSym = tree.symbol + final def enclClass = basisSym.enclClass + final def derivedFlags: Long = basisSym.flags & flagsMask | flagsExtra + } + + trait DerivedFromClassDef extends DerivedFromMemberDef { + def tree: ClassDef + } + + trait DerivedFromValDef extends DerivedFromMemberDef { def tree: ValDef /** Which meta-annotation is associated with this kind of entity. @@ -245,14 +274,8 @@ trait MethodSynthesis { */ def category: Symbol - // Final methods to make the rest easier to reason about. - final def mods = tree.mods - final def basisSym = tree.symbol - final def enclClass = basisSym.enclClass - final def completer(sym: Symbol) = namerOf(sym).accessorTypeCompleter(tree, isSetter) final def fieldSelection = Select(This(enclClass), basisSym) - final def derivedFlags: Long = basisSym.flags & flagsMask | flagsExtra final def derivedMods: Modifiers = mods & flagsMask | flagsExtra mapAnnotations (_ => Nil) def derivedSym: Symbol = tree.symbol @@ -312,6 +335,19 @@ trait MethodSynthesis { private def setterDef = DefDef(derivedSym, setterRhs) override def derivedTree: Tree = if (setterParam == NoSymbol) EmptyTree else setterDef } + + /** A synthetic method which performs the implicit conversion implied by + * the declaration of an implicit class. Yet to be written. + */ + case class ImplicitClassConverter(tree: ClassDef) extends DerivedFromClassDef { + def completer(sym: Symbol): Type = ??? + def derivedSym: Symbol = ??? + def derivedTree: DefDef = ??? + def flagsExtra: Long = ??? + def flagsMask: Long = ??? + def name: TermName = ??? + } + case class Getter(tree: ValDef) extends DerivedGetter { def name = tree.name def category = GetterTargetClass diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index c5fb13a5a9..6b27c27652 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -665,6 +665,10 @@ trait Namers extends MethodSynthesis { "If possible, define " + tree.symbol + " in " + owner.skipPackageObject + " instead." ) } + + // Suggested location only. + if (mods.isImplicit) + enterImplicitClass(tree) } // this logic is needed in case typer was interrupted half diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index ed263cbbef..105c2c0b98 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -263,8 +263,8 @@ abstract class TreeCheckers extends Analyzer { tree match { case x: PackageDef => - if (sym.ownerChain contains currentOwner) () - else fail(sym + " owner chain does not contain currentOwner " + currentOwner) + if ((sym.ownerChain contains currentOwner) || currentOwner == definitions.EmptyPackageClass) () + else fail(sym + " owner chain does not contain currentOwner " + currentOwner + sym.ownerChain) case _ => def cond(s: Symbol) = !s.isTerm || s.isMethod || s == sym.owner diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index e17a271dd0..6efa595d99 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -252,12 +252,17 @@ trait TypeDiagnostics { } "" // no elaborable variance situation found } - def foundReqMsg(found: Type, req: Type): String = ( - withDisambiguation(Nil, found, req)( + // TODO - figure out how to avoid doing any work at all + // when the message will never be seen. I though context.reportErrors + // being false would do that, but if I return "<suppressed>" under + // that condition, I see it. + def foundReqMsg(found: Type, req: Type): String = { + def baseMessage = ( ";\n found : " + found.toLongString + existentialContext(found) + explainAlias(found) + "\n required: " + req + existentialContext(req) + explainAlias(req) - ) + explainVariance(found, req) - ) + ) + withDisambiguation(Nil, found, req)(baseMessage) + explainVariance(found, req) + } case class TypeDiag(tp: Type, sym: Symbol) extends Ordered[TypeDiag] { // save the name because it will be mutated until it has been @@ -307,16 +312,37 @@ trait TypeDiagnostics { ) } } - private def typeDiags(locals: List[Symbol], types: Type*): List[TypeDiag] = { - object SymExtractor { - def unapply(x: Any) = x match { - case t @ ConstantType(_) => Some(t -> t.underlying.typeSymbol) - case t @ TypeRef(_, sym, _) => if (locals contains sym) None else Some(t -> sym) - case _ => None + /** This is tricky stuff - we need to traverse types deeply to + * explain name ambiguities, which may occur anywhere. However + * when lub explosions come through it knocks us into an n^2 + * disaster, see SI-5580. This is trying to perform the initial + * filtering of possibly ambiguous types in a sufficiently + * aggressive way that the state space won't explode. + */ + private def typeDiags(locals: List[Symbol], types0: Type*): List[TypeDiag] = { + val types = types0.toList + // If two different type diag instances are seen for a given + // key (either the string representation of a type, or the simple + // name of a symbol) then keep them for disambiguation. + val strings = mutable.Map[String, Set[TypeDiag]]() withDefaultValue Set() + val names = mutable.Map[Name, Set[TypeDiag]]() withDefaultValue Set() + + def record(t: Type, sym: Symbol) = { + val diag = TypeDiag(t, sym) + + strings("" + t) += diag + names(sym.name) += diag + } + for (tpe <- types ; t <- tpe) { + t match { + case ConstantType(_) => record(t, t.underlying.typeSymbol) + case TypeRef(_, sym, _) => record(t, sym) + case _ => () } } - for (tp <- types.toList; SymExtractor(t, sym) <- tp) yield TypeDiag(t, sym) + val collisions = strings.values ++ names.values filter (_.size > 1) + collisions.flatten.toList } /** The distinct pairs from an ordered list. */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index ad48712a32..49ce9712df 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1158,6 +1158,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val qtpe = qual.tpe.widen ( !isPastTyper && qual.isTerm + && !qual.isInstanceOf[Super] && ((qual.symbol eq null) || !qual.symbol.isTerm || qual.symbol.isValue) && !qtpe.isError && !qtpe.typeSymbol.isBottomClass @@ -1173,12 +1174,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { ) } - def adaptToMember(qual: Tree, searchTemplate: Type): Tree = - adaptToMember(qual, searchTemplate, true, true) - def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean): Tree = - adaptToMember(qual, searchTemplate, reportAmbiguous, true) - - def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = { + def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean = true, saveErrors: Boolean = true): Tree = { if (isAdaptableWithView(qual)) { qual.tpe.widen.normalize match { case et: ExistentialType => @@ -1284,8 +1280,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { unit.error(clazz.pos, "value class may not be a "+ (if (clazz.owner.isTerm) "local class" else "member of another class")) val constr = clazz.primaryConstructor - if ((constr hasFlag (PRIVATE | PROTECTED)) || constr.privateWithin != NoSymbol) - unit.error(constr.pos, "value class must have public primary constructor") clazz.info.decls.toList.filter(acc => acc.isMethod && (acc hasFlag PARAMACCESSOR)) match { case List(acc) => def isUnderlyingAcc(sym: Symbol) = diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala index 53c767be20..bc74717366 100644 --- a/src/compiler/scala/tools/nsc/util/Position.scala +++ b/src/compiler/scala/tools/nsc/util/Position.scala @@ -33,6 +33,16 @@ object Position { } } +/** + * A tree does not directly store a Position. It stores a TreeAnnotation, which /typically/ is a Position. + * + * A TreeAnnotion may encompass more than just a Position, though, depending on the exact subclass of TreeAnnotation. + */ +trait TreeAnnotation { + def pos: Position +} + + /** The Position class and its subclasses represent positions of ASTs and symbols. * Except for NoPosition and FakePos, every position refers to a SourceFile * and to an offset in the sourcefile (its `point`). For batch compilation, @@ -77,7 +87,8 @@ object Position { * pos.makeTransparent converts an opaque range position into a transparent one. * returns all other positions unchanged. */ -trait Position { +trait Position extends TreeAnnotation { + def pos: Position = this /** An optional value containing the source file referred to by this position, or * None if not defined. |