From c66d3b0d445bdb96cb363a1bf492672aff3bdcf0 Mon Sep 17 00:00:00 2001 From: Gilles Dubochet Date: Tue, 6 Jul 2010 16:07:31 +0000 Subject: [scaladoc] Implements documentation of higher-k... [scaladoc] Implements documentation of higher-kinded entities. Closes #3618. Review by moors. --- .../scala/tools/nsc/doc/html/page/Template.scala | 37 +++++++------ .../scala/tools/nsc/doc/model/Entity.scala | 22 ++++---- .../scala/tools/nsc/doc/model/ModelFactory.scala | 60 ++++++++++++---------- 3 files changed, 63 insertions(+), 56 deletions(-) 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 a43c89adad..06a2aaee6b 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -349,7 +349,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { case None => NodeSeq.Empty case Some(tpe) => xml.Text(pre) ++ typeToHtml(tpe, hasLinks) } - bound0(hi, " <: ") ++ bound0(lo, " >: ") + bound0(lo, " >: ") ++ bound0(hi, " <: ") } def visibility(mbr: MemberEntity): Option[comment.Paragraph] = { @@ -379,23 +379,25 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { { kindToString(mbr) } - { if (mbr.isConstructor) tpl.name else mbr.name }{ - def tparamsToHtml(tpss: List[TypeParam]): NodeSeq = - if (tpss.isEmpty) NodeSeq.Empty else { - def tparam0(tp: TypeParam): NodeSeq = - { tp.variance + tp.name }{ boundsToHtml(tp.hi, tp.lo, hasLinks)} - def tparams0(tpss: List[TypeParam]): NodeSeq = (tpss: @unchecked) match { - case tp :: Nil => tparam0(tp) - case tp :: tps => tparam0(tp) ++ Text(", ") ++ tparams0(tps) + { if (mbr.isConstructor) tpl.name else mbr.name } + { + def tparamsToHtml(mbr: Entity): NodeSeq = mbr match { + case hk: HigherKinded => + val tpss = hk.typeParams + if (tpss.isEmpty) NodeSeq.Empty else { + def tparam0(tp: TypeParam): NodeSeq = + { tp.variance + tp.name }{ tparamsToHtml(tp) }{ boundsToHtml(tp.hi, tp.lo, hasLinks)} + def tparams0(tpss: List[TypeParam]): NodeSeq = (tpss: @unchecked) match { + case tp :: Nil => tparam0(tp) + case tp :: tps => tparam0(tp) ++ Text(", ") ++ tparams0(tps) + } + [{ tparams0(tpss) }] } - [{ tparams0(tpss) }] - } - mbr match { - case trt: Trait => tparamsToHtml(trt.typeParams) - case dfe: Def => tparamsToHtml(dfe.typeParams) - case _ => NodeSeq.Empty + case _ => NodeSeq.Empty } - }{ + tparamsToHtml(mbr) + } + { def paramsToHtml(vlsss: List[List[ValueParam]]): NodeSeq = { def param0(vl: ValueParam): NodeSeq = // notice the }{ in the next lines, they are necessary to avoid a undesired withspace in output @@ -423,7 +425,8 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { case dfe: Def => paramsToHtml(dfe.valueParams) case _ => NodeSeq.Empty } - }{ + } + { mbr match { case tpl: DocTemplateEntity if (!tpl.isPackage) => tpl.parentType match { diff --git a/src/compiler/scala/tools/nsc/doc/model/Entity.scala b/src/compiler/scala/tools/nsc/doc/model/Entity.scala index f36f560777..8c47fd7fbb 100644 --- a/src/compiler/scala/tools/nsc/doc/model/Entity.scala +++ b/src/compiler/scala/tools/nsc/doc/model/Entity.scala @@ -19,7 +19,6 @@ trait Entity { override def toString = qualifiedName } - /** A class, trait, object or package. A package is represented as an instance * of the `Package` subclass. A class, trait, object or package may be * directly an instance of `WeakTemplateEntity` if it is not ''documentable'' @@ -61,13 +60,16 @@ trait MemberEntity extends Entity { def isTemplate: Boolean } +trait HigherKinded extends Entity { + def typeParams: List[TypeParam] +} + /** A ''documentable'' class, trait or object (that is, a documentation page * will be generated for it in the current site). */ trait DocTemplateEntity extends TemplateEntity with MemberEntity { def toRoot: List[DocTemplateEntity] def inSource: Option[(io.AbstractFile, Int)] def sourceUrl: Option[java.net.URL] - def typeParams: List[TypeParam] def parentType: Option[TypeEntity] def parentTemplates: List[TemplateEntity] def linearization: List[TemplateEntity] @@ -98,12 +100,12 @@ trait DocTemplateEntity extends TemplateEntity with MemberEntity { } /** A ''documentable'' trait. */ -trait Trait extends DocTemplateEntity { +trait Trait extends DocTemplateEntity with HigherKinded { def valueParams : List[List[ValueParam]] } /** A ''documentable'' class. */ -trait Class extends Trait { +trait Class extends Trait with HigherKinded { def primaryConstructor: Option[Constructor] def constructors: List[Constructor] def isCaseClass: Boolean @@ -128,8 +130,7 @@ trait NonTemplateMemberEntity extends MemberEntity { } /** A method (`def`) of a ''documentable'' class, trait or object. */ -trait Def extends NonTemplateMemberEntity { - def typeParams: List[TypeParam] +trait Def extends NonTemplateMemberEntity with HigherKinded { def valueParams : List[List[ValueParam]] } @@ -143,26 +144,23 @@ trait Constructor extends NonTemplateMemberEntity { trait Val extends NonTemplateMemberEntity /** An abstract type of a ''documentable'' class, trait or object. */ -trait AbstractType extends NonTemplateMemberEntity { - // TODO: typeParams +trait AbstractType extends NonTemplateMemberEntity with HigherKinded { def lo: Option[TypeEntity] def hi: Option[TypeEntity] } /** An abstract type of a ''documentable'' class, trait or object. */ -trait AliasType extends NonTemplateMemberEntity { - // TODO: typeParams +trait AliasType extends NonTemplateMemberEntity with HigherKinded { def alias: TypeEntity } trait ParameterEntity extends Entity { - def inTemplate: DocTemplateEntity def isTypeParam: Boolean def isValueParam: Boolean } /** A type parameter to a class or trait or to a method. */ -trait TypeParam extends ParameterEntity { +trait TypeParam extends ParameterEntity with HigherKinded { def variance: String def lo: Option[TypeEntity] def hi: Option[TypeEntity] diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 72844201ba..218d3158f9 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -49,7 +49,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory /** Provides a default implementation for instances of the `Entity` type. */ abstract class EntityImpl(val sym: Symbol, inTpl: => TemplateImpl) extends Entity { val name = optimize(sym.nameString) - def inTemplate = inTpl + def inTemplate: TemplateImpl = inTpl def toRoot: List[EntityImpl] = this :: inTpl.toRoot def qualifiedName = name } @@ -57,7 +57,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory /** Provides a default implementation for instances of the `WeakTemplateEntity` type. It must be instantiated as a * `SymbolicEntity` to access the compiler symbol that underlies the entity. */ trait TemplateImpl extends EntityImpl with TemplateEntity { - override def qualifiedName = if (inTemplate.isRootPackage) name else optimize(inTemplate.qualifiedName + "." + name) + override def qualifiedName: String = + if (inTemplate.isRootPackage) name else optimize(inTemplate.qualifiedName + "." + name) def isPackage = sym.isPackage def isTrait = sym.isTrait def isClass = sym.isClass && !sym.isTrait @@ -141,7 +142,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory * * The owner of the template (as a full template); * * All ancestors of the template (as weak templates); * * All non-package members (including other templates, as full templates). */ - abstract class DocTemplateImpl(sym: Symbol, inTpl: => DocTemplateImpl) extends MemberImpl(sym, inTpl) with TemplateImpl with DocTemplateEntity { + abstract class DocTemplateImpl(sym: Symbol, inTpl: => DocTemplateImpl) extends MemberImpl(sym, inTpl) with TemplateImpl with HigherKindedImpl with DocTemplateEntity { //if (inTpl != null) println("mbr " + sym + " in " + (inTpl.toRoot map (_.sym)).mkString(" > ")) templatesCache += (sym -> this) lazy val definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "." + name) @@ -159,11 +160,11 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory } else None } - def typeParams = if (sym.isClass) sym.typeParams map (makeTypeParam(_, this)) else Nil def parentTemplates = sym.info.parents map { x: Type => makeTemplate(x.typeSymbol) } - def parentType = + def parentType = { if (sym.isPackage) None else - Some(makeType(RefinedType(sym.tpe.parents filter (_ != ScalaObjectClass.tpe), EmptyScope), inTpl)) + Some(makeType(RefinedType((sym.tpe.parents filter (_ != ScalaObjectClass.tpe)) map { _.asSeenFrom(sym.thisType, sym) }, EmptyScope), inTpl)) + } val linearization = { val tpls = sym.ancestors filter { _ != ScalaObjectClass } map { makeTemplate(_) } tpls map { @@ -219,21 +220,28 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory }} } - abstract class ParameterImpl(sym: Symbol, inTpl: => DocTemplateImpl) extends EntityImpl(sym, inTpl) with ParameterEntity { + abstract class ParameterImpl(sym: Symbol, inTpl: => TemplateImpl) extends EntityImpl(sym, inTpl) with ParameterEntity { override def inTemplate = inTpl } private trait TypeBoundsImpl extends EntityImpl { - def lo = sym.info.normalize match { - case TypeBounds(lo, hi) if lo.typeSymbol != NothingClass => Some(makeType(lo, inTemplate, sym)) + def lo = sym.info.bounds match { + case TypeBounds(lo, hi) if lo.typeSymbol != NothingClass => + Some(makeType(appliedType(lo, sym.info.typeParams map {_.tpe}), inTemplate)) case _ => None } - def hi = sym.info.normalize match { - case TypeBounds(lo, hi) if hi.typeSymbol != AnyClass => Some(makeType(hi, inTemplate, sym)) + def hi = sym.info.bounds match { + case TypeBounds(lo, hi) if hi.typeSymbol != AnyClass => + Some(makeType(appliedType(hi, sym.info.typeParams map {_.tpe}), inTemplate)) case _ => None } } + trait HigherKindedImpl extends EntityImpl with HigherKinded { + def typeParams = + sym.typeParams map (makeTypeParam(_, inTemplate)) + } + /* ============== MAKER METHODS ============== */ /** */ @@ -348,10 +356,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory override def isVar = true }) else if (bSym.isMethod && !bSym.isGetterOrSetter && !bSym.isConstructor && !bSym.isModule) - Some(new NonTemplateParamMemberImpl(bSym, inTpl) with Def { + Some(new NonTemplateParamMemberImpl(bSym, inTpl) with HigherKindedImpl with Def { override def isDef = true - def typeParams = - sym.tpe.typeParams map (makeTypeParam(_, inTpl)) }) else if (bSym.isConstructor) Some(new NonTemplateParamMemberImpl(bSym, inTpl) with Constructor { @@ -363,13 +369,13 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory override def isVal = true }) else if (bSym.isAbstractType) - Some(new NonTemplateMemberImpl(bSym, inTpl) with TypeBoundsImpl with AbstractType { + Some(new NonTemplateMemberImpl(bSym, inTpl) with TypeBoundsImpl with HigherKindedImpl with AbstractType { override def isAbstractType = true }) else if (bSym.isAliasType) - Some(new NonTemplateMemberImpl(bSym, inTpl) with AliasType { + Some(new NonTemplateMemberImpl(bSym, inTpl) with HigherKindedImpl with AliasType { override def isAliasType = true - def alias = makeType(sym.tpe, inTpl, sym) + def alias = makeType(appliedType(sym.tpe, sym.info.typeParams map {_.tpe}).normalize, inTpl, sym) }) else if (bSym.isPackage) inTpl match { case inPkg: PackageImpl => makePackage(bSym, inPkg) } @@ -391,8 +397,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory } /** */ - def makeTypeParam(aSym: Symbol, inTpl: => DocTemplateImpl): TypeParam = { - new ParameterImpl(aSym, inTpl) with TypeBoundsImpl with TypeParam { + def makeTypeParam(aSym: Symbol, inTpl: => TemplateImpl): TypeParam = + new ParameterImpl(aSym, inTpl) with TypeBoundsImpl with HigherKindedImpl with TypeParam { def isTypeParam = true def isValueParam = false def variance: String = { @@ -401,7 +407,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory else "" } } - } /** */ def makeValueParam(aSym: Symbol, inTpl: => DocTemplateImpl): ValueParam = { @@ -452,9 +457,14 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory nameBuffer append sep appendTypes0(tps, sep) } - private def appendType0(tpe: Type): Unit = tpe.normalize match { + private def checkFunctionType(tpe: TypeRef): Boolean = { + val TypeRef(_, sym, args) = tpe + (args.length > 0) && (args.length - 1 <= definitions.MaxFunctionArity) && + (sym == definitions.FunctionClass(args.length - 1)) + } + private def appendType0(tpe: Type): Unit = tpe match { /* Type refs */ - case tp: TypeRef if (definitions.isFunctionType(tp)) => + case tp: TypeRef if (checkFunctionType(tp)) => nameBuffer append '(' appendTypes0(tp.args.init, ", ") nameBuffer append ") ⇒ " @@ -492,11 +502,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory } /* Polymorphic types */ case PolyType(tparams, result) if (!tparams.isEmpty) => - appendType0(result) - nameBuffer append '[' - appendTypes0(tparams map (_.tpe), ", ") // TODO: actually print the polytype's symbols (not just types) - nameBuffer append ']' - /* Eval-by-name types */ + throw new Error("Polymorphic type '" + tpe + "' cannot be printed as a type") case PolyType(tparams, result) if (tparams.isEmpty) => nameBuffer append '⇒' appendType0(result) -- cgit v1.2.3