diff options
36 files changed, 592 insertions, 111 deletions
diff --git a/build-ant-macros.xml b/build-ant-macros.xml index 816a18b13f..ea5652770e 100644 --- a/build-ant-macros.xml +++ b/build-ant-macros.xml @@ -408,12 +408,44 @@ <if> <equals arg1="${@{project}.docroot}" arg2="NOT SET"/> <then> - <scaladoc destdir="${build-docs.dir}/@{project}" doctitle="${@{project}.description}" docfooter="epfl" docversion="${version.number}" sourcepath="${src.dir}" classpathref="docs.@{project}.build.path" srcdir="${src.dir}/${@{project}.srcdir}" addparams="${scalac.args.all}" implicits="on" diagrams="on" groups="on" rawOutput="${scaladoc.raw.output}" noPrefixes="${scaladoc.no.prefixes}" docUncompilable="${src.dir}/library-aux" skipPackages="${@{project}.skipPackages}"> + <scaladoc + destdir="${build-docs.dir}/@{project}" + doctitle="${@{project}.description}" + docfooter="epfl" + docversion="${version.number}" + sourcepath="${src.dir}" + classpathref="docs.@{project}.build.path" + srcdir="${src.dir}/${@{project}.srcdir}" + addparams="${scalac.args.all}" + docsourceurl="${scaladoc.url}€{FILE_PATH}.scala#L1" + implicits="on" + diagrams="on" + groups="on" + rawOutput="${scaladoc.raw.output}" + noPrefixes="${scaladoc.no.prefixes}" + docUncompilable="${src.dir}/library-aux" + skipPackages="${@{project}.skipPackages}"> <includes/> </scaladoc> </then> <else> - <scaladoc destdir="${build-docs.dir}/@{project}" doctitle="${@{project}.description}" docfooter="epfl" docversion="${version.number}" sourcepath="${src.dir}" classpathref="docs.@{project}.build.path" srcdir="${src.dir}/${@{project}.srcdir}" docRootContent="${src.dir}/@{project}/${@{project}.docroot}" addparams="${scalac.args.all}" implicits="on" diagrams="on" groups="on" rawOutput="${scaladoc.raw.output}" noPrefixes="${scaladoc.no.prefixes}" docUncompilable="${src.dir}/library-aux" skipPackages="${@{project}.skipPackages}"> + <scaladoc docRootContent="${src.dir}/@{project}/${@{project}.docroot}" + destdir="${build-docs.dir}/@{project}" + doctitle="${@{project}.description}" + docfooter="epfl" + docversion="${version.number}" + sourcepath="${src.dir}" + classpathref="docs.@{project}.build.path" + srcdir="${src.dir}/${@{project}.srcdir}" + addparams="${scalac.args.all}" + docsourceurl="${scaladoc.url}€{FILE_PATH}.scala#L1" + implicits="on" + diagrams="on" + groups="on" + rawOutput="${scaladoc.raw.output}" + noPrefixes="${scaladoc.no.prefixes}" + docUncompilable="${src.dir}/library-aux" + skipPackages="${@{project}.skipPackages}"> <includes/> </scaladoc> </else> diff --git a/build.number b/build.number index 51674b6915..63a55339b9 100644 --- a/build.number +++ b/build.number @@ -1,7 +1,7 @@ #Tue Sep 11 19:21:09 CEST 2007 version.major=2 version.minor=11 -version.patch=0 +version.patch=1 # This is the -N part of a version. if it's 0, it's dropped from maven versions. version.bnum=0 @@ -304,6 +304,7 @@ TODO: necessary cross suffix (usually something like "_2.11.0-M6". --> <prepareCross name="scala-xml" /> <prepareCross name="scala-parser-combinators" /> + <property name="scala-continuations-plugin.cross.suffix" value="_${scala.full.version}"/> <prepareCross name="scala-continuations-plugin" /> <prepareCross name="scala-continuations-library"/> <prepareCross name="scala-swing"/> diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala index e0bc478fad..fde0aca584 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala @@ -86,7 +86,7 @@ trait Logic extends Debugging { def mayBeNull: Boolean // compute the domain and return it (call registerNull first!) - def domainSyms: Option[Set[Sym]] + def domainSyms: Option[mutable.LinkedHashSet[Sym]] // the symbol for this variable being equal to its statically known type // (only available if registerEquality has been called for that type before) @@ -162,11 +162,18 @@ trait Logic extends Debugging { // to govern how much time we spend analyzing matches for unreachability/exhaustivity object AnalysisBudget { - private val budgetProp = scala.sys.Prop[Int]("scalac.patmat.analysisBudget") + private val budgetProp = scala.sys.Prop[String]("scalac.patmat.analysisBudget") private val budgetOff = "off" val max: Int = { val DefaultBudget = 256 - budgetProp.option.getOrElse(if (budgetProp.get.equalsIgnoreCase("off")) Integer.MAX_VALUE else DefaultBudget) + budgetProp.option match { + case Some(`budgetOff`) => + Integer.MAX_VALUE + case Some(x) => + x.toInt + case None => + DefaultBudget + } } abstract class Exception(val advice: String) extends RuntimeException("CNF budget exceeded") @@ -197,7 +204,7 @@ trait Logic extends Debugging { def removeVarEq(props: List[Prop], modelNull: Boolean = false): (Formula, List[Formula]) = { val start = if (Statistics.canEnable) Statistics.startTimer(patmatAnaVarEq) else null - val vars = new scala.collection.mutable.HashSet[Var] + val vars = mutable.LinkedHashSet[Var]() object gatherEqualities extends PropTraverser { override def apply(p: Prop) = p match { @@ -334,9 +341,9 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { // we enumerate the subtypes of the full type, as that allows us to filter out more types statically, // once we go to run-time checks (on Const's), convert them to checkable types // TODO: there seems to be bug for singleton domains (variable does not show up in model) - lazy val domain: Option[Set[Const]] = { - val subConsts = enumerateSubtypes(staticTp).map{ tps => - tps.toSet[Type].map{ tp => + lazy val domain: Option[mutable.LinkedHashSet[Const]] = { + val subConsts: Option[mutable.LinkedHashSet[Const]] = enumerateSubtypes(staticTp).map { tps => + mutable.LinkedHashSet(tps: _*).map{ tp => val domainC = TypeConst(tp) registerEquality(domainC) domainC @@ -479,7 +486,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { } // accessing after calling registerNull will result in inconsistencies - lazy val domainSyms: Option[Set[Sym]] = domain map { _ map symForEqualsTo } + lazy val domainSyms: Option[collection.mutable.LinkedHashSet[Sym]] = domain map { _ map symForEqualsTo } lazy val symForStaticTp: Option[Sym] = symForEqualsTo.get(TypeConst(staticTpCheckable)) diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 87da565142..9b9e641cad 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -346,12 +346,14 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT * performance hit for the compiler as a whole. */ override def atOwner[A](tree: Tree, owner: Symbol)(trans: => A): A = { + val savedValid = validCurrentOwner if (owner.isClass) validCurrentOwner = true val savedLocalTyper = localTyper localTyper = localTyper.atOwner(tree, if (owner.isModule) owner.moduleClass else owner) typers = typers updated (owner, localTyper) val result = super.atOwner(tree, owner)(trans) localTyper = savedLocalTyper + validCurrentOwner = savedValid typers -= owner result } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9f557f4aa5..3690750e42 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -197,7 +197,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper !from.isError && !to.isError && context.implicitsEnabled - && (inferView(EmptyTree, from, to, reportAmbiguous = false) != EmptyTree) + && (inferView(context.tree, from, to, reportAmbiguous = false, saveErrors = true) != EmptyTree) + // SI-8230 / SI-8463 We'd like to change this to `saveErrors = false`, but can't. + // For now, we can at least pass in `context.tree` rather then `EmptyTree` so as + // to avoid unpositioned type errors. ) def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean): Tree = @@ -1041,11 +1044,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (tree.tpe <:< AnyTpe) pt.dealias match { case TypeRef(_, UnitClass, _) => // (12) if (settings.warnValueDiscard) - context.unit.warning(tree.pos, "discarded non-Unit value") + context.warning(tree.pos, "discarded non-Unit value") return typedPos(tree.pos, mode, pt)(Block(List(tree), Literal(Constant(())))) case TypeRef(_, sym, _) if isNumericValueClass(sym) && isNumericSubType(tree.tpe, pt) => if (settings.warnNumericWiden) - context.unit.warning(tree.pos, "implicit numeric widening") + context.warning(tree.pos, "implicit numeric widening") return typedPos(tree.pos, mode, pt)(Select(tree, "to" + sym.name)) case _ => } @@ -2479,7 +2482,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper * an alternative TODO: add partial function AST node or equivalent and get rid of this synthesis --> do everything in uncurry (or later) * however, note that pattern matching codegen is designed to run *before* uncurry */ - def synthesizePartialFunction(paramName: TermName, paramPos: Position, tree: Tree, mode: Mode, pt: Type): Tree = { + def synthesizePartialFunction(paramName: TermName, paramPos: Position, paramSynthetic: Boolean, + tree: Tree, mode: Mode, pt: Type): Tree = { assert(pt.typeSymbol == PartialFunctionClass, s"PartialFunction synthesis for match in $tree requires PartialFunction expected type, but got $pt.") val targs = pt.dealiasWiden.typeArgs @@ -2507,7 +2511,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val casesTrue = cases map (c => deriveCaseDef(c)(x => atPos(x.pos.focus)(TRUE)).duplicate.asInstanceOf[CaseDef]) // must generate a new tree every time - def selector: Tree = gen.mkUnchecked( + def selector(paramSym: Symbol): Tree = gen.mkUnchecked( if (sel != EmptyTree) sel.duplicate else atPos(tree.pos.focusStart)( // SI-6925: subsume type of the selector to `argTp` @@ -2518,7 +2522,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // hence the cast, which will be erased in posterasure // (the cast originally caused extremely weird types to show up // in test/scaladoc/run/SI-5933.scala because `variantToSkolem` was missing `tpSym.initialize`) - gen.mkCastPreservingAnnotations(Ident(paramName), argTp) + gen.mkCastPreservingAnnotations(Ident(paramSym), argTp) )) def mkParam(methodSym: Symbol, tp: Type = argTp) = @@ -2546,14 +2550,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper methodSym setInfo polyType(List(A1, B1), MethodType(paramSyms, B1.tpe)) val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) - // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - paramSyms foreach (methodBodyTyper.context.scope enter _) + if (!paramSynthetic) methodBodyTyper.context.scope enter x // First, type without the default case; only the cases provided // by the user are typed. The LUB of these becomes `B`, the lower // bound of `B1`, which in turn is the result type of the default // case - val match0 = methodBodyTyper.typedMatch(selector, cases, mode, resTp) + val match0 = methodBodyTyper.typedMatch(selector(x), cases, mode, resTp) val matchResTp = match0.tpe B1 setInfo TypeBounds.lower(matchResTp) // patch info @@ -2627,11 +2630,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val paramSym = mkParam(methodSym) val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - methodBodyTyper.context.scope enter paramSym + if (!paramSynthetic) methodBodyTyper.context.scope enter paramSym methodSym setInfo MethodType(List(paramSym), BooleanTpe) val defaultCase = mkDefaultCase(FALSE) - val match_ = methodBodyTyper.typedMatch(selector, casesTrue :+ defaultCase, mode, BooleanTpe) + val match_ = methodBodyTyper.typedMatch(selector(paramSym), casesTrue :+ defaultCase, mode, BooleanTpe) DefDef(methodSym, methodBodyTyper.virtualizedMatch(match_, mode, BooleanTpe)) } @@ -2645,10 +2648,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper methodSym setInfo MethodType(List(paramSym), AnyTpe) val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) - // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - methodBodyTyper.context.scope enter paramSym + if (!paramSynthetic) methodBodyTyper.context.scope enter paramSym - val match_ = methodBodyTyper.typedMatch(selector, cases, mode, resTp) + val match_ = methodBodyTyper.typedMatch(selector(paramSym), cases, mode, resTp) val matchResTp = match_.tpe methodSym setInfo MethodType(List(paramSym), matchResTp) // patch info @@ -2920,7 +2922,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val p = fun.vparams.head if (p.tpt.tpe == null) p.tpt setType outerTyper.typedType(p.tpt).tpe - outerTyper.synthesizePartialFunction(p.name, p.pos, fun.body, mode, pt) + outerTyper.synthesizePartialFunction(p.name, p.pos, paramSynthetic = false, fun.body, mode, pt) // Use synthesizeSAMFunction to expand `(p1: T1, ..., pN: TN) => body` // to an instance of the corresponding anonymous subclass of `pt`. @@ -4207,7 +4209,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val cases = tree.cases if (selector == EmptyTree) { if (pt.typeSymbol == PartialFunctionClass) - synthesizePartialFunction(newTermName(context.unit.fresh.newName("x")), tree.pos, tree, mode, pt) + synthesizePartialFunction(newTermName(context.unit.fresh.newName("x")), tree.pos, paramSynthetic = true, tree, mode, pt) else { val arity = if (isFunctionType(pt)) pt.dealiasWiden.typeArgs.length - 1 else 1 val params = for (i <- List.range(0, arity)) yield @@ -5109,7 +5111,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def isPlausible(m: Symbol) = m.alternatives exists (m => requiresNoArgs(m.info)) def maybeWarn(s: String): Unit = { - def warn(message: String) = context.unit.warning(lit.pos, s"$message Did you forget the interpolator?") + def warn(message: String) = context.warning(lit.pos, s"$message Did you forget the interpolator?") def suspiciousSym(name: TermName) = context.lookupSymbol(name, _ => true).symbol def suspiciousExpr = InterpolatorCodeRegex findFirstIn s def suspiciousIdents = InterpolatorIdentRegex findAllIn s map (s => suspiciousSym(s drop 1)) diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 25d78f4e6f..bf560a21e5 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -490,8 +490,10 @@ trait Definitions extends api.StandardDefinitions { lazy val TypeCreatorClass = getClassIfDefined("scala.reflect.api.TypeCreator") // defined in scala-reflect.jar, so we need to be careful lazy val TreeCreatorClass = getClassIfDefined("scala.reflect.api.TreeCreator") // defined in scala-reflect.jar, so we need to be careful - lazy val BlackboxContextClass = getClassIfDefined("scala.reflect.macros.blackbox.Context") // defined in scala-reflect.jar, so we need to be careful - lazy val WhiteboxContextClass = getClassIfDefined("scala.reflect.macros.whitebox.Context") // defined in scala-reflect.jar, so we need to be careful + private def Context_210 = if (settings.isScala211) NoSymbol else getClassIfDefined("scala.reflect.macros.Context") // needed under -Xsource:2.10 + lazy val BlackboxContextClass = getClassIfDefined("scala.reflect.macros.blackbox.Context").orElse(Context_210) // defined in scala-reflect.jar, so we need to be careful + + lazy val WhiteboxContextClass = getClassIfDefined("scala.reflect.macros.whitebox.Context").orElse(Context_210) // defined in scala-reflect.jar, so we need to be careful def MacroContextPrefix = BlackboxContextClass.map(sym => getMemberMethod(sym, nme.prefix)) def MacroContextPrefixType = BlackboxContextClass.map(sym => getTypeMember(sym, tpnme.PrefixType)) def MacroContextUniverse = BlackboxContextClass.map(sym => getMemberMethod(sym, nme.universe)) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index eb56f4ba81..f26315c538 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -4113,8 +4113,8 @@ trait Types def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol], depth: Depth): Boolean = { def isSubArg(t1: Type, t2: Type, variance: Variance) = ( - (variance.isContravariant || isSubType(t1, t2, depth)) - && (variance.isCovariant || isSubType(t2, t1, depth)) + (variance.isCovariant || isSubType(t2, t1, depth)) // The order of these two checks can be material for performance (SI-8478) + && (variance.isContravariant || isSubType(t1, t2, depth)) ) corresponds3(tps1, tps2, mapList(tparams)(_.variance))(isSubArg) diff --git a/src/reflect/scala/reflect/internal/pickling/Translations.scala b/src/reflect/scala/reflect/internal/pickling/Translations.scala index e56cf796cb..d924cb3a0c 100644 --- a/src/reflect/scala/reflect/internal/pickling/Translations.scala +++ b/src/reflect/scala/reflect/internal/pickling/Translations.scala @@ -62,21 +62,22 @@ trait Translations { } def picklerTag(tpe: Type): Int = tpe match { - case NoType => NOtpe - case NoPrefix => NOPREFIXtpe - case _: ThisType => THIStpe - case _: SingleType => SINGLEtpe - case _: SuperType => SUPERtpe - case _: ConstantType => CONSTANTtpe - case _: TypeBounds => TYPEBOUNDStpe - case _: TypeRef => TYPEREFtpe - case _: RefinedType => REFINEDtpe - case _: ClassInfoType => CLASSINFOtpe - case _: MethodType => METHODtpe - case _: PolyType => POLYtpe - case _: NullaryMethodType => POLYtpe // bad juju, distinct ints are not at a premium! - case _: ExistentialType => EXISTENTIALtpe - case _: AnnotatedType => ANNOTATEDtpe + case NoType => NOtpe + case NoPrefix => NOPREFIXtpe + case _: ThisType => THIStpe + case _: SingleType => SINGLEtpe + case _: SuperType => SUPERtpe + case _: ConstantType => CONSTANTtpe + case _: TypeBounds => TYPEBOUNDStpe + case _: TypeRef => TYPEREFtpe + case _: RefinedType => REFINEDtpe + case _: ClassInfoType => CLASSINFOtpe + case _: MethodType => METHODtpe + case _: PolyType => POLYtpe + case _: NullaryMethodType => POLYtpe // bad juju, distinct ints are not at a premium! + case _: ExistentialType => EXISTENTIALtpe + case StaticallyAnnotatedType(_, _) => ANNOTATEDtpe + case _: AnnotatedType => picklerTag(tpe.underlying) } def picklerSubTag(tree: Tree): Int = tree match { diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index a96bed4696..ce0eadc04f 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -402,7 +402,13 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) private val crashRecovery: PartialFunction[Throwable, Boolean] = { case ex: Throwable => - echo(intp.global.throwableAsString(ex)) + val (err, explain) = ( + if (intp.isInitializeComplete) + (intp.global.throwableAsString(ex), "") + else + (ex.getMessage, "The compiler did not initialize.\n") + ) + echo(err) ex match { case _: NoSuchMethodError | _: NoClassDefFoundError => @@ -410,7 +416,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) throw ex case _ => def fn(): Boolean = - try in.readYesOrNo(replayQuestionMessage, { echo("\nYou must enter y or n.") ; fn() }) + try in.readYesOrNo(explain + replayQuestionMessage, { echo("\nYou must enter y or n.") ; fn() }) catch { case _: RuntimeException => false } if (fn()) replay() diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 9c853fb514..47d97dd4dd 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -117,8 +117,10 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set private def _initSources = List(new BatchSourceFile("<init>", "class $repl_$init { }")) private def _initialize() = { try { - // todo. if this crashes, REPL will hang - new _compiler.Run() compileSources _initSources + // if this crashes, REPL will hang its head in shame + val run = new _compiler.Run() + assert(run.typerPhase != NoPhase, "REPL requires a typer phase.") + run compileSources _initSources _initializeComplete = true true } @@ -384,6 +386,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set def compileSourcesKeepingRun(sources: SourceFile*) = { val run = new Run() + assert(run.typerPhase != NoPhase, "REPL requires a typer phase.") reporter.reset() run compileSources sources.toList (!reporter.hasErrors, run) diff --git a/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala b/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala index 51fab3082e..07d619bca5 100644 --- a/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala +++ b/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala @@ -55,6 +55,8 @@ trait ReplGlobal extends Global { // newNamer(rootContext(unit)).enterSym(unit.body) } } + // add to initial or terminal phase to sanity check Run at construction + override val requires = List("typer") // ensure they didn't -Ystop-after:parser } override protected def computePhaseDescriptors: List[SubComponent] = { diff --git a/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala b/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala index d721a96ad7..a0dd154d2e 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala @@ -97,7 +97,9 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) { "selected2.png", "selected-right-implicits.png", "selected-implicits.png", - "unselected.png" + "unselected.png", + + "permalink.png" ) /** Generates the Scaladoc site for a model into the site root. diff --git a/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala b/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala index f6373e9e97..295bae5bef 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala @@ -14,6 +14,7 @@ import base.comment._ import model._ import scala.xml.NodeSeq +import scala.xml.Elem import scala.xml.dtd.{DocType, PublicID} import scala.collection._ import java.io.Writer @@ -219,4 +220,28 @@ abstract class HtmlPage extends Page { thisPage => else if (ety.isObject) "object_big.png" else if (ety.isPackage) "package_big.png" else "class_big.png" // FIXME: an entity *should* fall into one of the above categories, but AnyRef is somehow not + + def permalink(template: Entity, isSelf: Boolean = true): Elem = + <span class="permalink"> + <a href={ memberToUrl(template, isSelf) } title="Permalink" target="_top"> + <img src={ relativeLinkTo(List("permalink.png", "lib")) } /> + </a> + </span> + + def memberToUrl(template: Entity, isSelf: Boolean = true): String = { + val (signature: Option[String], containingTemplate: TemplateEntity) = template match { + case dte: DocTemplateEntity if (!isSelf) => (Some(dte.signature), dte.inTemplate) + case dte: DocTemplateEntity => (None, dte) + case me: MemberEntity => (Some(me.signature), me.inTemplate) + case tpl => (None, tpl) + } + + def hashFromPath(templatePath: List[String]): String = + ((templatePath.head.replace(".html", "") :: templatePath.tail).reverse).mkString(".") + + val containingTemplatePath = templateToPath(containingTemplate) + val url = "../" * (containingTemplatePath.size - 1) + "index.html" + val hash = hashFromPath(containingTemplatePath) + s"$url#$hash" + signature.map("@" + _).getOrElse("") + } } diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala index 26ee005d3e..b5a8d1ac36 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala @@ -15,7 +15,7 @@ import base.comment._ import model._ import model.diagram._ -import scala.xml.{ NodeSeq, Text, UnprefixedAttribute } +import scala.xml.{Elem, NodeSeq, Text, UnprefixedAttribute} import scala.language.postfixOps import scala.collection.mutable. { Set, HashSet } @@ -110,7 +110,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp <img src={ relativeLinkTo(List(docEntityKindToBigImage(tpl), "lib")) }/> }} { owner } - <h1>{ displayName }</h1> + <h1>{ displayName }</h1> { permalink(tpl) } </div> { signature(tpl, isSelf = true) } @@ -306,9 +306,6 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp <xml:group> <div id="comment" class="fullcommenttop">{ memberToCommentBodyHtml(mbr, inTpl, isSelf = true) }</div> </xml:group> - case dte: DocTemplateEntity if mbr.comment.isDefined => - // comment of inner, documented class (only short comment, full comment is on the class' own page) - memberToInlineCommentHtml(mbr, isSelf) case _ => // comment of non-class member or non-documentented inner class val commentBody = memberToCommentBodyHtml(mbr, inTpl, isSelf = false) @@ -723,6 +720,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp /** name, tparams, params, result */ def signature(mbr: MemberEntity, isSelf: Boolean, isReduced: Boolean = false): NodeSeq = { + def inside(hasLinks: Boolean, nameLink: String = ""): NodeSeq = <xml:group> <span class="modifier_kind"> @@ -833,11 +831,11 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp </xml:group> mbr match { case dte: DocTemplateEntity if !isSelf => - <h4 class="signature">{ inside(hasLinks = true, nameLink = relativeLinkTo(dte)) }</h4> + <h4 class="signature">{ inside(hasLinks = true, nameLink = relativeLinkTo(dte)) }</h4> ++ permalink(dte, isSelf) case _ if isSelf => <h4 id="signature" class="signature">{ inside(hasLinks = true) }</h4> case _ => - <h4 class="signature">{ inside(hasLinks = true) }</h4> + <h4 class="signature">{ inside(hasLinks = true) }</h4> ++ permalink(mbr) } } diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js index c201b324e7..3f5cfb4b52 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js @@ -1,5 +1,5 @@ // © 2009–2010 EPFL/LAMP -// code by Gilles Dubochet with contributions by Johannes Rudolph and "spiros" +// code by Gilles Dubochet with contributions by Johannes Rudolph, "spiros" and Marcin Kubala var topLevelTemplates = undefined; var topLevelPackages = undefined; @@ -11,7 +11,7 @@ var focusFilterState = undefined; var title = $(document).attr('title'); -var lastHash = ""; +var lastFragment = ""; $(document).ready(function() { $('body').layout({ @@ -24,9 +24,13 @@ $(document).ready(function() { ,north__paneSelector: ".ui-west-north" }); $('iframe').bind("load", function(){ - var subtitle = $(this).contents().find('title').text(); - $(document).attr('title', (title ? title + " - " : "") + subtitle); - + try { + var subtitle = $(this).contents().find('title').text(); + $(document).attr('title', (title ? title + " - " : "") + subtitle); + } catch (e) { + // Chrome doesn't allow reading the iframe's contents when + // used on the local file system. + } setUrlFragmentFromFrameSrc(); }); @@ -64,21 +68,43 @@ $(document).ready(function() { // Set the iframe's src according to the fragment of the current url. // fragment = "#scala.Either" => iframe url = "scala/Either.html" // fragment = "#scala.Either@isRight:Boolean" => iframe url = "scala/Either.html#isRight:Boolean" +// fragment = "#scalaz.iteratee.package@>@>[E,A]=scalaz.iteratee.package.Iteratee[E,A]" => iframe url = "scalaz/iteratee/package.html#>@>[E,A]=scalaz.iteratee.package.Iteratee[E,A]" function setFrameSrcFromUrlFragment() { - var fragment = location.hash.slice(1); - if(fragment) { - var loc = fragment.split("@")[0].replace(/\./g, "/"); - if(loc.indexOf(".html") < 0) loc += ".html"; - if(fragment.indexOf('@') > 0) loc += ("#" + fragment.split("@", 2)[1]); - frames["template"].location.replace(loc); - } - else - frames["template"].location.replace("package.html"); + + function extractLoc(fragment) { + var loc = fragment.split('@')[0].replace(/\./g, "/"); + if (loc.indexOf(".html") < 0) { + loc += ".html"; + } + return loc; + } + + function extractMemberSig(fragment) { + var splitIdx = fragment.indexOf('@'); + if (splitIdx < 0) { + return; + } + return fragment.substr(splitIdx + 1); + } + + var fragment = location.hash.slice(1); + if (fragment) { + var locWithMemeberSig = extractLoc(fragment); + var memberSig = extractMemberSig(fragment); + if (memberSig) { + locWithMemeberSig += "#" + memberSig; + } + frames["template"].location.replace(locWithMemeberSig); + } else { + console.log("empty fragment detected"); + frames["template"].location.replace("package.html"); + } } // Set the url fragment according to the src of the iframe "template". // iframe url = "scala/Either.html" => url fragment = "#scala.Either" // iframe url = "scala/Either.html#isRight:Boolean" => url fragment = "#scala.Either@isRight:Boolean" +// iframe url = "scalaz/iteratee/package.html#>@>[E,A]=scalaz.iteratee.package.Iteratee[E,A]" => fragment = "#scalaz.iteratee.package@>@>[E,A]=scalaz.iteratee.package.Iteratee[E,A]" function setUrlFragmentFromFrameSrc() { try { var commonLength = location.pathname.lastIndexOf("/"); diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/permalink.png b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/permalink.png Binary files differnew file mode 100644 index 0000000000..d54bc93f6a --- /dev/null +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/permalink.png diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css index b066027f04..35f66cd5df 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css @@ -397,6 +397,37 @@ div.members > ol > li:last-child { margin-bottom: 5px; } +#template .members li .permalink { + position: absolute; + top: 5px; + right: 5px; +} + +#definition .permalink { + position: absolute; + top: 10px; + right: 15px; +} + +#definition .permalink a { + color: #EBEBEB; +} + +#template .members li .permalink, +#definition .permalink a { + display: none; +} + +#template .members li:hover .permalink, +#definition:hover .permalink a { + display: block; +} + +#template .members li .permalink a, +#definition .permalink a { + text-decoration: none; + font-weight: bold; +} /* Comments text formating */ diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js index 6d1caf6d50..1ebcb67f04 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js @@ -1,23 +1,57 @@ // © 2009–2010 EPFL/LAMP -// code by Gilles Dubochet with contributions by Pedro Furlanetto +// code by Gilles Dubochet with contributions by Pedro Furlanetto and Marcin Kubala $(document).ready(function(){ + var controls = { + visibility: { + publicOnly: $("#visbl").find("> ol > li.public"), + all: $("#visbl").find("> ol > li.all") + } + }; + // Escapes special characters and returns a valid jQuery selector function escapeJquery(str){ - return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1'); + return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=<>\|])/g, '\\$1'); } - // highlight and jump to selected member - if (window.location.hash) { - var temp = window.location.hash.replace('#', ''); - var elem = '#'+escapeJquery(temp); + function toggleVisibilityFilter(ctrlToEnable, ctrToDisable) { + if (ctrlToEnable.hasClass("out")) { + ctrlToEnable.removeClass("out").addClass("in"); + ctrToDisable.removeClass("in").addClass("out"); + filter(); + } + } + + controls.visibility.publicOnly.click(function () { + toggleVisibilityFilter(controls.visibility.publicOnly, controls.visibility.all); + }); - window.scrollTo(0, 0); - $(elem).parent().effect("highlight", {color: "#FFCC85"}, 3000); - $('html,body').animate({scrollTop:$(elem).parent().offset().top}, 1000); + controls.visibility.all.click(function () { + toggleVisibilityFilter(controls.visibility.all, controls.visibility.publicOnly); + }); + + function exposeMember(jqElem) { + var jqElemParent = jqElem.parent(), + parentName = jqElemParent.attr("name"), + linearizationName = /^([^#]*)(#.*)?$/gi.exec(parentName)[1]; + + // switch visibility filter if necessary + if (jqElemParent.attr("visbl") == "prt") { + toggleVisibilityFilter(controls.visibility.all, controls.visibility.publicOnly); + } + + // toggle appropriate linearization buttons + if (linearizationName) { + $("#linearization li.out[name='" + linearizationName + "']").removeClass("out").addClass("in"); + } + + filter(); + window.scrollTo(0, 0); + jqElemParent.effect("highlight", {color: "#FFCC85"}, 3000); + $('html,body').animate({scrollTop: jqElemParent.offset().top}, 1000); } - + var isHiddenClass = function (name) { return name == 'scala.Any' || name == 'scala.AnyRef'; @@ -97,7 +131,7 @@ $(document).ready(function(){ else if ($(this).hasClass("out")) { $(this).removeClass("out"); $(this).addClass("in"); - }; + } filter(); }); @@ -109,7 +143,7 @@ $(document).ready(function(){ else if ($(this).hasClass("out")) { $(this).removeClass("out"); $(this).addClass("in"); - }; + } filter(); }); @@ -147,32 +181,18 @@ $(document).ready(function(){ }); $("#visbl > ol > li.public").click(function() { if ($(this).hasClass("out")) { - $(this).removeClass("out").addClass("in"); - $("#visbl > ol > li.all").removeClass("in").addClass("out"); - filter(); - }; - }) - $("#visbl > ol > li.all").click(function() { - if ($(this).hasClass("out")) { - $(this).removeClass("out").addClass("in"); - $("#visbl > ol > li.public").removeClass("in").addClass("out"); - filter(); - }; - }); - $("#order > ol > li.alpha").click(function() { - if ($(this).hasClass("out")) { orderAlpha(); - }; + } }) $("#order > ol > li.inherit").click(function() { if ($(this).hasClass("out")) { orderInherit(); - }; + } }); $("#order > ol > li.group").click(function() { if ($(this).hasClass("out")) { orderGroup(); - }; + } }); $("#groupedMembers").hide(); @@ -181,7 +201,7 @@ $(document).ready(function(){ // Create tooltips $(".extype").add(".defval").tooltip({ tip: "#tooltip", - position:"top center", + position: "top center", predelay: 500, onBeforeShow: function(ev) { $(this.getTip()).text(this.getTrigger().attr("name")); @@ -233,6 +253,20 @@ $(document).ready(function(){ windowTitle(); if ($("#order > ol > li.group").length == 1) { orderGroup(); }; + + function findElementByHash(locationHash) { + var temp = locationHash.replace('#', ''); + var memberSelector = '#' + escapeJquery(temp); + return $(memberSelector); + } + + // highlight and jump to selected member + if (window.location.hash) { + var jqElem = findElementByHash(window.location.hash); + if (jqElem.length > 0) { + exposeMember(jqElem); + } + } }); function orderAlpha() { diff --git a/test/files/neg/t8430.check b/test/files/neg/t8430.check new file mode 100644 index 0000000000..7c6a73ce53 --- /dev/null +++ b/test/files/neg/t8430.check @@ -0,0 +1,27 @@ +t8430.scala:15: warning: match may not be exhaustive. +It would fail on the following inputs: ??, LetC, LetF, LetL(IntLit), LetP + (tree: Tree) => tree match {case LetL(CharLit) => ??? } + ^ +t8430.scala:16: warning: match may not be exhaustive. +It would fail on the following inputs: ??, LetC, LetF, LetL(IntLit), LetP + (tree: Tree) => tree match {case LetL(CharLit) => ??? } + ^ +t8430.scala:17: warning: match may not be exhaustive. +It would fail on the following inputs: ??, LetC, LetF, LetL(IntLit), LetP + (tree: Tree) => tree match {case LetL(CharLit) => ??? } + ^ +t8430.scala:18: warning: match may not be exhaustive. +It would fail on the following inputs: ??, LetC, LetF, LetL(IntLit), LetP + (tree: Tree) => tree match {case LetL(CharLit) => ??? } + ^ +t8430.scala:19: warning: match may not be exhaustive. +It would fail on the following inputs: ??, LetC, LetF, LetL(IntLit), LetP + (tree: Tree) => tree match {case LetL(CharLit) => ??? } + ^ +t8430.scala:20: warning: match may not be exhaustive. +It would fail on the following inputs: ??, LetC, LetF, LetL(IntLit), LetP + (tree: Tree) => tree match {case LetL(CharLit) => ??? } + ^ +error: No warnings can be incurred under -Xfatal-warnings. +6 warnings found +one error found diff --git a/test/files/neg/t8430.flags b/test/files/neg/t8430.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/t8430.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/t8430.scala b/test/files/neg/t8430.scala new file mode 100644 index 0000000000..4166b08a0a --- /dev/null +++ b/test/files/neg/t8430.scala @@ -0,0 +1,32 @@ +sealed trait CL3Literal +case object IntLit extends CL3Literal +case object CharLit extends CL3Literal +case object BooleanLit extends CL3Literal +case object UnitLit extends CL3Literal + + +sealed trait Tree +case class LetL(value: CL3Literal) extends Tree +case object LetP extends Tree +case object LetC extends Tree +case object LetF extends Tree + +object Test { + (tree: Tree) => tree match {case LetL(CharLit) => ??? } + (tree: Tree) => tree match {case LetL(CharLit) => ??? } + (tree: Tree) => tree match {case LetL(CharLit) => ??? } + (tree: Tree) => tree match {case LetL(CharLit) => ??? } + (tree: Tree) => tree match {case LetL(CharLit) => ??? } + (tree: Tree) => tree match {case LetL(CharLit) => ??? } + // After the first patch for SI-8430, we achieve stability: all of + // these get the same warning: + // + // ??, LetC, LetF, LetL(IntLit), LetP + // + // Before, it was non-deterministic. + // + // However, we our list of counter examples is itself non-exhaustive. + // We need to rework counter example generation to fix that. + // + // That work is the subject of SI-7746 +} diff --git a/test/files/neg/t8450.check b/test/files/neg/t8450.check new file mode 100644 index 0000000000..eeabb9730c --- /dev/null +++ b/test/files/neg/t8450.check @@ -0,0 +1,6 @@ +t8450.scala:5: warning: implicit numeric widening + def elapsed: Foo = (System.nanoTime - 100L).foo + ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/t8450.flags b/test/files/neg/t8450.flags new file mode 100644 index 0000000000..9a1332d7af --- /dev/null +++ b/test/files/neg/t8450.flags @@ -0,0 +1 @@ +-Ywarn-numeric-widen -Xfatal-warnings
\ No newline at end of file diff --git a/test/files/neg/t8450.scala b/test/files/neg/t8450.scala new file mode 100644 index 0000000000..f20ed2bc31 --- /dev/null +++ b/test/files/neg/t8450.scala @@ -0,0 +1,12 @@ +trait Foo + +class WarnWidening { + implicit class FooDouble(d: Double) { def foo = new Foo {} } + def elapsed: Foo = (System.nanoTime - 100L).foo +} + +class NoWarnWidening { + implicit class FooLong(l: Long) { def foo = new Foo {} } + implicit class FooDouble(d: Double) { def foo = new Foo {} } + def elapsed: Foo = (System.nanoTime - 100L).foo +} diff --git a/test/files/neg/t8463.check b/test/files/neg/t8463.check new file mode 100644 index 0000000000..1a3eea2870 --- /dev/null +++ b/test/files/neg/t8463.check @@ -0,0 +1,10 @@ +t8463.scala:5: error: type mismatch; + found : Long + required: ?T[Long] +Note that implicit conversions are not applicable because they are ambiguous: + both method longWrapper in class LowPriorityImplicits of type (x: Long)scala.runtime.RichLong + and method ArrowAssoc in object Predef of type [A](self: A)ArrowAssoc[A] + are possible conversion functions from Long to ?T[Long] + insertCell(Foo(5)) + ^ +one error found diff --git a/test/files/neg/t8463.scala b/test/files/neg/t8463.scala new file mode 100644 index 0000000000..7c954fd834 --- /dev/null +++ b/test/files/neg/t8463.scala @@ -0,0 +1,38 @@ +object Test { + case class Foo[+T[_]](activity:T[Long]) + type Cell[T] = T + def insertCell(u:Foo[Cell]) = ??? + insertCell(Foo(5)) +} + +/* If SI-8230 is fixed, and `viewExists` is changed to no longer leak + ambiguity errors, you might expect the check file for this test to + change as folloes: + +@@ -1,18 +1,10 @@ +-t8463.scala:5: error: no type parameters for method apply: (activity: +- --- because --- +-argument expression's type is not compatible with formal parameter ty ++t8463.scala:5: error: type mismatch; + found : Long + required: ?T[Long] ++Note that implicit conversions are not applicable because they are am ++ both method longWrapper in class LowPriorityImplicits of type (x: Lo ++ and method ArrowAssoc in object Predef of type [A](self: A)ArrowAsso ++ are possible conversion functions from Long to ?T[Long] + insertCell(Foo(5)) +- ^ +-t8463.scala:5: error: type mismatch; +- found : Long(5L) +- required: T[Long] +- insertCell(Foo(5)) +- ^ +-t8463.scala:5: error: type mismatch; +- found : Test.Foo[T] +- required: Test.Foo[Test.Cell] +- insertCell(Foo(5)) +- ^ +-three errors found ++ ^ ++one error found +*/ diff --git a/test/files/pos/t8329.scala b/test/files/pos/t8329.scala new file mode 100644 index 0000000000..fcd5e50b37 --- /dev/null +++ b/test/files/pos/t8329.scala @@ -0,0 +1,29 @@ +object Test { + def pf(pf: PartialFunction[Any, Unit]) = () + def f1(pf: Function[Any, Unit]) = () + + class A1; class B1 + def test1(x: String, x1: String, default: String) = pf { + case _ if ( + x.isEmpty + && default.isEmpty // was binding to synthetic param + && x1.isEmpty // was binding to synthetic param + ) => + x.isEmpty + default.isEmpty // was binding to synthetic param + x1.isEmpty // was binding to synthetic param + new A1; new B1 + } + + def test2(x: String, x1: String, default: String) = f1 { + case _ if ( + x.isEmpty + && default.isEmpty + && x1.isEmpty + ) => + x.isEmpty + default.isEmpty + x1.isEmpty + new A1; new B1 + } +} diff --git a/test/files/pos/t8497/A_1.scala b/test/files/pos/t8497/A_1.scala new file mode 100644 index 0000000000..6a76b0ee99 --- /dev/null +++ b/test/files/pos/t8497/A_1.scala @@ -0,0 +1,13 @@ +package p { + object Crash { + def e(s: (String @java.lang.Deprecated)): Unit = () + def f(s: (String @nonStatic)): Unit = () + } + object Ok { + def g(s: (String @nonStatic @static)): Unit = () + def h(s: (String @static)): Unit = () + } +} + +class nonStatic extends scala.annotation.Annotation +class static extends scala.annotation.StaticAnnotation diff --git a/test/files/pos/t8497/B_2.scala b/test/files/pos/t8497/B_2.scala new file mode 100644 index 0000000000..efe2edf2c3 --- /dev/null +++ b/test/files/pos/t8497/B_2.scala @@ -0,0 +1 @@ +package p { object Test { Crash } } diff --git a/test/files/run/t7992.scala b/test/files/run/t7992.scala new file mode 100644 index 0000000000..fde231b961 --- /dev/null +++ b/test/files/run/t7992.scala @@ -0,0 +1,20 @@ +class C { + def foo: Int = 0 +} + +class D extends C { + override def foo: Int = { + val f = () => { + class C // comment this line to fix. + D.super.foo // no super accessor generated here! + // java.lang.VerifyError: (class: D$$anonfun$1, method: apply$mcI$sp signature: ()I) Illegal use of nonvirtual function call + } + f() + } +} + +object Test { + def main(args: Array[String]) { + new D().foo + } +} diff --git a/test/files/run/t7992b.scala b/test/files/run/t7992b.scala new file mode 100644 index 0000000000..6fe1f990d5 --- /dev/null +++ b/test/files/run/t7992b.scala @@ -0,0 +1,18 @@ +class C { + def foo: Int = 0 +} + +class E extends C { + override def foo: Int = { + (None: Option[Int]).getOrElse { + class C + E.super.foo + } + } +} + +object Test { + def main(args: Array[String]) { + new E().foo + } +} diff --git a/test/scaladoc/resources/SI-8144.scala b/test/scaladoc/resources/SI-8144.scala new file mode 100644 index 0000000000..7b225acb32 --- /dev/null +++ b/test/scaladoc/resources/SI-8144.scala @@ -0,0 +1,17 @@ +package some.pack + +class SomeType(arg: String) { + + type TypeAlias = String + + def >@<(): TypeAlias = "Tricky method name" + + def >#<(): Int = 1 + +} + +object SomeType { + + val someVal = "Some arbitrary companion object value" + +} diff --git a/test/scaladoc/resources/SI-8514.scala b/test/scaladoc/resources/SI-8514.scala new file mode 100644 index 0000000000..4c5476604b --- /dev/null +++ b/test/scaladoc/resources/SI-8514.scala @@ -0,0 +1,10 @@ +package a { + class DeveloperApi extends scala.annotation.StaticAnnotation + + /** Some doc here */ + @DeveloperApi + class A + + @DeveloperApi + class B +} diff --git a/test/scaladoc/scalacheck/HtmlFactoryTest.scala b/test/scaladoc/scalacheck/HtmlFactoryTest.scala index 56328ea875..ef70e0bf21 100644 --- a/test/scaladoc/scalacheck/HtmlFactoryTest.scala +++ b/test/scaladoc/scalacheck/HtmlFactoryTest.scala @@ -149,7 +149,6 @@ object Test extends Properties("HtmlFactory") { result } - def shortComments(root: scala.xml.Node) = XMLUtil.stripGroup(root).descendant.flatMap { case e: scala.xml.Elem => { @@ -417,7 +416,7 @@ object Test extends Properties("HtmlFactory") { checkText("SI_5054_q1.scala")( (None,"""def test(): Int""", true) //Disabled because the full signature is now displayed - //(None,"""def test(implicit lost: Int): Int""", false) + //(None, """def test(implicit lost: Int): Int""", false) ) property("SI-5054: Use cases should keep their flags - final should not be lost") = @@ -564,7 +563,7 @@ object Test extends Properties("HtmlFactory") { property("Comment inheritance: Correct explicit inheritance for override") = checkText("explicit-inheritance-override.scala")( (Some("InheritDocDerived"), - """def function[T](arg1: T, arg2: String): Double + """def function[T](arg1: T, arg2: String): Double Starting line Starting line The base comment. And another sentence... @@ -591,7 +590,7 @@ object Test extends Properties("HtmlFactory") { property("Comment inheritance: Correct explicit inheritance for usecase") = checkText("explicit-inheritance-usecase.scala")( (Some("UseCaseInheritDoc"), - """def function[T](arg1: T, arg2: String): Double + """def function[T](arg1: T, arg2: String): Double [use case] Starting line [use case] Starting line The base comment. And another sentence... @@ -740,5 +739,78 @@ object Test extends Properties("HtmlFactory") { case node: scala.xml.Node => true case _ => false } + + property("SI-8514: No inconsistencies") = + checkText("SI-8514.scala")( + (Some("a/package"), + """class A extends AnyRef + Some doc here + Some doc here + Annotations @DeveloperApi() + """, true), + (Some("a/package"), + """class B extends AnyRef + Annotations @DeveloperApi() + """, true) + ) + } + + // SI-8144 + { + implicit class AttributesAwareNode(val node: NodeSeq) { + + def \@(attrName: String): String = + node \ ("@" + attrName) text + + def \@(attrName: String, attrValue: String): NodeSeq = + node filter { _ \ ("@" + attrName) exists (_.text == attrValue) } + } + + implicit class AssertionAwareNode(node: scala.xml.NodeSeq) { + + def assertTypeLink(expectedUrl: String): Boolean = { + val linkElement: NodeSeq = node \\ "div" \@ ("id", "definition") \\ "span" \@ ("class", "permalink") \ "a" + linkElement \@ "href" == expectedUrl && linkElement \@ "target" == "_top" + } + + def assertMemberLink(group: String)(memberName: String, expectedUrl: String): Boolean = { + val linkElement: NodeSeq = node \\ "div" \@ ("id", group) \\ "li" \@ ("name", memberName) \\ "span" \@ ("class", "permalink") \ "a" + linkElement \@ "href" == expectedUrl && linkElement \@ "target" == "_top" + } + + } + + val files = createTemplates("SI-8144.scala") + + def check(pagePath: String)(f: NodeSeq => org.scalacheck.Prop): org.scalacheck.Prop = + files(pagePath) match { + case node: scala.xml.Node => f(XMLUtil.stripGroup(node)) + case _ => false + } + + property("SI-8144: Members' permalink - package") = check("some/package.html") { node => + ("type link" |: node.assertTypeLink("../index.html#some.package")) && + ("member: some.pack" |: node.assertMemberLink("values")("some.pack", "../index.html#some.package@pack")) + } + + property("SI-8144: Members' permalink - inner package") = check("some/pack/package.html") { node => + ("type link" |: node.assertTypeLink("../../index.html#some.pack.package")) && + ("member: SomeType (object)" |: node.assertMemberLink("values")("some.pack.SomeType", "../../index.html#some.pack.package@SomeType")) && + ("member: SomeType (class)" |: node.assertMemberLink("types")("some.pack.SomeType", "../../index.html#some.pack.package@SomeTypeextendsAnyRef")) + } + + property("SI-8144: Members' permalink - companion object") = check("some/pack/SomeType$.html") { node => + ("type link" |: node.assertTypeLink("../../index.html#some.pack.SomeType$")) && + ("member: someVal" |: node.assertMemberLink("allMembers")("some.pack.SomeType#someVal", "../../index.html#some.pack.SomeType$@someVal:String")) + } + + property("SI-8144: Members' permalink - class") = check("some/pack/SomeType.html") { node => + ("type link" |: node.assertTypeLink("../../index.html#some.pack.SomeType")) && + ("constructor " |: node.assertMemberLink("constructors")("some.pack.SomeType#<init>", "../../index.html#some.pack.SomeType@<init>(arg:String):some.pack.SomeType")) && + ( "member: type TypeAlias" |: node.assertMemberLink("types")("some.pack.SomeType.TypeAlias", "../../index.html#some.pack.SomeType@TypeAlias=String")) && + ( "member: def >#<():Int " |: node.assertMemberLink("values")("some.pack.SomeType#>#<", "../../index.html#some.pack.SomeType@>#<():Int")) && + ( "member: def >@<():TypeAlias " |: node.assertMemberLink("values")("some.pack.SomeType#>@<", "../../index.html#some.pack.SomeType@>@<():SomeType.this.TypeAlias")) + } + } } diff --git a/versions.properties b/versions.properties index 4e0485fdd0..0e56f731ed 100644 --- a/versions.properties +++ b/versions.properties @@ -1,20 +1,20 @@ -#Fri, 04 Apr 2014 23:11:56 +0200 +#Wed, 16 Apr 2014 11:13:08 +0200 # NOTE: this file determines the content of the scala-distribution # via scala-dist-pom.xml and scala-library-all-pom.xml # when adding new properties that influence a release, # also add them to the update.versions mechanism in build.xml, # which is used by scala-release-2.11.x in scala/jenkins-scripts -starr.version=2.11.0-RC4 +starr.version=2.11.0 starr.use.released=1 # These are the versions of the modules that go with this release. # These properties are used during PR validation and in dbuild builds. # e.g. 2.11.0-RC1, 2.11 -scala.binary.version=2.11.0-RC4 +scala.binary.version=2.11 # e.g. 2.11.0-RC1, 2.11.0, 2.11.1-RC1, 2.11.1 # this defines the dependency on scala-continuations-plugin in scala-dist's pom -scala.full.version=2.11.0-RC4 +scala.full.version=2.11.0 # external modules shipped with distribution, as specified by scala-library-all's pom scala-xml.version.number=1.0.1 |