From d61d2c93d788fdf01ad2497b9c6bb69ab9d6a397 Mon Sep 17 00:00:00 2001 From: Antonio Cunei Date: Mon, 12 Apr 2010 16:37:39 +0000 Subject: Merged revisions 21467,21471-21482,21486-21487 ... Merged revisions 21467,21471-21482,21486-21487 via svnmerge from https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk ........ r21467 | plocinic | 2010-04-12 10:09:26 +0200 (Mon, 12 Apr 2010) | 1 line Closes #2757. No review. ........ r21471 | odersky | 2010-04-12 13:52:39 +0200 (Mon, 12 Apr 2010) | 1 line Closes #3224. Review by retronym. ........ r21472 | odersky | 2010-04-12 13:53:05 +0200 (Mon, 12 Apr 2010) | 1 line Cosmetic renamings. No review. ........ r21473 | phaller | 2010-04-12 13:59:29 +0200 (Mon, 12 Apr 2010) | 1 line actors.UncaughtException stores most recent sender. Default output for unhandled exceptions can be disabled using actors.Debug. Review by plocinic. ........ r21474 | phaller | 2010-04-12 14:00:10 +0200 (Mon, 12 Apr 2010) | 1 line Improved deprecation warnings in actors package object. No review. ........ r21475 | phaller | 2010-04-12 14:02:51 +0200 (Mon, 12 Apr 2010) | 1 line Another test for see #2017. No review. ........ r21476 | phaller | 2010-04-12 15:25:57 +0200 (Mon, 12 Apr 2010) | 1 line Attempting to unblock partest by handling AssertionErrors. No review. ........ r21477 | dubochet | 2010-04-12 15:29:05 +0200 (Mon, 12 Apr 2010) | 1 line [scaladoc] meta-documentation (attributes, definition classes, etc.) is available for members that do not have a comment. No review. ........ r21478 | dubochet | 2010-04-12 16:16:01 +0200 (Mon, 12 Apr 2010) | 1 line [scaladoc] Dangerous HTML (that can break Scaladoc) is stripped out of comments and replaced by corresponding wiki syntax when possible. No review. ........ r21479 | dubochet | 2010-04-12 16:29:47 +0200 (Mon, 12 Apr 2010) | 1 line [scaladoc] Not all 23 AbstractFunction classes are listed in the left list. No review. ........ r21480 | dubochet | 2010-04-12 16:38:16 +0200 (Mon, 12 Apr 2010) | 1 line [scaladoc] More mitigation code for dangerous HTML tags. No review. ........ r21481 | malayeri | 2010-04-12 16:52:39 +0200 (Mon, 12 Apr 2010) | 1 line Move constructors to beginning of scaladoc html page; show implicit modifier in main list. Review by dubochet. ........ r21482 | rytz | 2010-04-12 17:12:56 +0200 (Mon, 12 Apr 2010) | 1 line fixed LOAD_MODULE for companions of primitive types. fixes .net build. review by dragos. ........ r21486 | odersky | 2010-04-12 17:26:20 +0200 (Mon, 12 Apr 2010) | 1 line changed testfile, to satisfy new diff algo (which should be reverted IMO). review by extempore. ........ r21487 | extempore | 2010-04-12 18:11:36 +0200 (Mon, 12 Apr 2010) | 1 line Some modifications to partest to improve output. Review by phaller. ........ --- src/actors/scala/actors/ActorTask.scala | 11 +- src/actors/scala/actors/Debug.scala | 31 +-- src/actors/scala/actors/ReactorTask.scala | 9 +- src/actors/scala/actors/UncaughtException.scala | 3 +- src/actors/scala/actors/package.scala | 8 +- .../scala/tools/nsc/backend/icode/GenICode.scala | 37 +-- .../nsc/dependencies/DependencyAnalysis.scala | 1 + .../scala/tools/nsc/doc/html/page/Index.scala | 14 +- .../scala/tools/nsc/doc/html/page/Template.scala | 262 +++++++++++---------- .../tools/nsc/doc/html/resource/lib/template.css | 10 +- .../scala/tools/nsc/doc/model/Entity.scala | 2 + .../scala/tools/nsc/doc/model/ModelFactory.scala | 6 + .../nsc/doc/model/comment/CommentFactory.scala | 24 +- .../scala/tools/nsc/typechecker/Infer.scala | 15 +- .../scala/tools/nsc/typechecker/Typers.scala | 6 +- .../scala/tools/nsc/typechecker/Unapplies.scala | 6 +- src/library/scala/native.scala | 22 +- src/partest/scala/tools/partest/Actions.scala | 2 +- src/partest/scala/tools/partest/Compilable.scala | 7 +- src/partest/scala/tools/partest/Dispatcher.scala | 19 +- src/partest/scala/tools/partest/Results.scala | 20 +- src/partest/scala/tools/partest/io/Logging.scala | 5 +- test/files/jvm/actor-uncaught-exception2.check | 2 + test/files/jvm/actor-uncaught-exception2.scala | 48 ++++ test/files/neg/t3224.check | 6 + test/files/neg/t3224.scala | 30 +++ 26 files changed, 386 insertions(+), 220 deletions(-) create mode 100644 test/files/jvm/actor-uncaught-exception2.check create mode 100644 test/files/jvm/actor-uncaught-exception2.scala create mode 100644 test/files/neg/t3224.check create mode 100755 test/files/neg/t3224.scala diff --git a/src/actors/scala/actors/ActorTask.scala b/src/actors/scala/actors/ActorTask.scala index bceea06072..2fa24f93af 100644 --- a/src/actors/scala/actors/ActorTask.scala +++ b/src/actors/scala/actors/ActorTask.scala @@ -30,9 +30,18 @@ private[actors] class ActorTask(actor: Actor, } protected override def terminateExecution(e: Exception) { + val senderInfo = try { Some(actor.sender) } catch { + case _: Exception => None + } + val uncaught = new UncaughtException(actor, + if (msg != null) Some(msg) else None, + senderInfo, + currentThread, + e) + actor.synchronized { if (!actor.links.isEmpty) - actor.exitLinked(e) + actor exitLinked uncaught } } diff --git a/src/actors/scala/actors/Debug.scala b/src/actors/scala/actors/Debug.scala index bad19b8aeb..f28156fc9a 100644 --- a/src/actors/scala/actors/Debug.scala +++ b/src/actors/scala/actors/Debug.scala @@ -11,22 +11,28 @@ package scala.actors /** + * Provides methods for generating debugging output. + * * @author Philipp Haller */ -object Debug { +object Debug extends Logger("") {} + +private[actors] class Logger(tag: String) { private var lev = 2 def level = lev def level_= (lev: Int) = { this.lev = lev } + private val tagString = if (tag == "") "" else " ["+tag+"]" + def info(s: String) = - if (lev > 2) System.out.println("Info: " + s) + if (lev > 2) System.out.println("Info" + tagString + ": " + s) def warning(s: String) = - if (lev > 1) System.err.println("Warning: " + s) + if (lev > 1) System.err.println("Warning" + tagString + ": " + s) def error(s: String) = - if (lev > 0) System.err.println("Error: " + s) + if (lev > 0) System.err.println("Error" + tagString + ": " + s) def doInfo(b: => Unit) = if (lev > 2) b @@ -38,18 +44,5 @@ object Debug { if (lev > 0) b } -class Debug(tag: String) { - private var lev = 2 - - def level = lev - def level_= (lev: Int) = { this.lev = lev } - - def info(s: String) = - if (lev > 2) System.out.println(tag + " (info): " + s) - - def warning(s: String) = - if (lev > 1) System.err.println(tag + " (warn): " + s) - - def error(s: String) = - if (lev > 0) System.err.println(tag + " (erro): " + s) -} +@deprecated("this class is going to be removed in a future release") +class Debug(tag: String) extends Logger(tag) {} diff --git a/src/actors/scala/actors/ReactorTask.scala b/src/actors/scala/actors/ReactorTask.scala index ac809f04ff..3f9ebb6fa7 100644 --- a/src/actors/scala/actors/ReactorTask.scala +++ b/src/actors/scala/actors/ReactorTask.scala @@ -53,12 +53,13 @@ private[actors] class ReactorTask[Msg >: Null](var reactor: Reactor[Msg], // print message on default error stream val msgException = "Uncaught exception in "+reactor+"\n" val msgMessage = if (msg != null) "Message: "+msg+"\n" else "" - Console.err.print(msgException + msgMessage) - e.printStackTrace() + Debug.doWarning { + Console.err.print(msgException + msgMessage) + e.printStackTrace() + } - val uncaught = new UncaughtException(reactor, if (msg != null) Some(msg) else None, currentThread, e) + terminateExecution(e) reactor.terminated() - terminateExecution(uncaught) } finally { suspendExecution() this.reactor = null diff --git a/src/actors/scala/actors/UncaughtException.scala b/src/actors/scala/actors/UncaughtException.scala index 30043465a1..54c28f66cf 100644 --- a/src/actors/scala/actors/UncaughtException.scala +++ b/src/actors/scala/actors/UncaughtException.scala @@ -21,11 +21,12 @@ package scala.actors */ class UncaughtException[Msg >: Null](val actor: Reactor[Msg], val message: Option[Msg], + val sender: Option[OutputChannel[Any]], val thread: Thread, cause: Exception) extends Exception(cause) { override def toString() = - "UncaughtException("+actor+","+message+","+cause+")" + "UncaughtException("+actor+","+message+","+sender+","+cause+")" } diff --git a/src/actors/scala/actors/package.scala b/src/actors/scala/actors/package.scala index 98170b83dd..66ba05b1dd 100644 --- a/src/actors/scala/actors/package.scala +++ b/src/actors/scala/actors/package.scala @@ -5,19 +5,19 @@ package object actors { // type of Reactors tracked by termination detector private[actors] type TrackedReactor = Reactor[A] forSome { type A >: Null } - @deprecated("use scala.actors.scheduler.ForkJoinScheduler instead") + @deprecated("use scheduler.ForkJoinScheduler instead") type FJTaskScheduler2 = scala.actors.scheduler.ForkJoinScheduler - @deprecated("use scala.actors.scheduler.ForkJoinScheduler instead") + @deprecated("use scheduler.ForkJoinScheduler instead") type TickedScheduler = scala.actors.scheduler.ForkJoinScheduler - @deprecated("use scala.actors.scheduler.ForkJoinScheduler instead") + @deprecated("use scheduler.ForkJoinScheduler instead") type WorkerThreadScheduler = scala.actors.scheduler.ForkJoinScheduler @deprecated("this class is going to be removed in a future release") type WorkerThread = java.lang.Thread - @deprecated("use scala.actors.scheduler.SingleThreadedScheduler instead") + @deprecated("use scheduler.SingleThreadedScheduler instead") type SingleThreadedScheduler = scala.actors.scheduler.SingleThreadedScheduler // This used to do a blind cast and throw a CCE after the package diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index a3b81862e6..b357dff25a 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -784,7 +784,7 @@ abstract class GenICode extends SubComponent { if (settings.debug.value) log("LOAD_MODULE from 'This': " + tree.symbol); assert(!tree.symbol.isPackageClass, "Cannot use package as value: " + tree) - ctx.bb.emit(LOAD_MODULE(tree.symbol), tree.pos) + genLoadModule(ctx, tree.symbol, tree.pos) generatedType = REFERENCE(tree.symbol) } else { ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos) @@ -803,21 +803,18 @@ abstract class GenICode extends SubComponent { log("LOAD_MODULE from Select(): " + tree.symbol); } assert(!tree.symbol.isPackageClass, "Cannot use package as value: " + tree) - ctx.bb.emit(LOAD_MODULE(tree.symbol), tree.pos) + genLoadModule(ctx, tree.symbol, tree.pos) ctx case Select(qualifier, selector) => - var sym = tree.symbol + val sym = tree.symbol generatedType = toTypeKind(sym.info) if (sym.isModule) { if (settings.debug.value) - log("LOAD_MODULE from Select(qualifier, selector): " + sym); + log("LOAD_MODULE from Select(qualifier, selector): " + sym) assert(!tree.symbol.isPackageClass, "Cannot use package as value: " + tree) - if (definitions.primitiveCompanions(sym)) - ctx.bb.emit(LOAD_MODULE(definitions.getModule("scala.runtime." + sym.name))) - else - ctx.bb.emit(LOAD_MODULE(sym), tree.pos); + genLoadModule(ctx, sym, tree.pos) ctx } else if (sym.isStaticMember) { ctx.bb.emit(LOAD_FIELD(sym, true), tree.pos) @@ -829,21 +826,22 @@ abstract class GenICode extends SubComponent { } case Ident(name) => - if (!tree.symbol.isPackage) { - if (tree.symbol.isModule) { + val sym = tree.symbol + if (!sym.isPackage) { + if (sym.isModule) { if (settings.debug.value) - log("LOAD_MODULE from Ident(name): " + tree.symbol); - assert(!tree.symbol.isPackageClass, "Cannot use package as value: " + tree) - ctx.bb.emit(LOAD_MODULE(tree.symbol), tree.pos) - generatedType = toTypeKind(tree.symbol.info) + log("LOAD_MODULE from Ident(name): " + sym) + assert(!sym.isPackageClass, "Cannot use package as value: " + tree) + genLoadModule(ctx, sym, tree.pos) + generatedType = toTypeKind(sym.info) } else { try { - val Some(l) = ctx.method.lookupLocal(tree.symbol) + val Some(l) = ctx.method.lookupLocal(sym) ctx.bb.emit(LOAD_LOCAL(l), tree.pos) generatedType = l.kind } catch { case ex: MatchError => - abort("symbol " + tree.symbol + " does not exist in " + ctx.method) + abort("symbol " + sym + " does not exist in " + ctx.method) } } } @@ -1037,6 +1035,13 @@ abstract class GenICode extends SubComponent { ctx1 } + private def genLoadModule(ctx: Context, sym: Symbol, pos: Position) { + if (definitions.primitiveCompanions(sym)) + ctx.bb.emit(LOAD_MODULE(definitions.getModule("scala.runtime." + sym.name)), pos) + else + ctx.bb.emit(LOAD_MODULE(sym), pos) + } + def genConversion(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean) = { if (cast) ctx.bb.emit(CALL_PRIMITIVE(Conversion(from, to))) diff --git a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala index c84e608bb7..4c7b1977bb 100644 --- a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala +++ b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala @@ -143,6 +143,7 @@ trait DependencyAnalysis extends SubComponent with Files { } } + dependencies.reset(source) for (d <- unit.depends; if (d.sourceFile != null)){ dependencies.depends(source, d.sourceFile); } diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala index 7bbd8ef821..8f1d537c43 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala @@ -43,10 +43,16 @@ class Index(universe: Universe) extends HtmlPage {
{ def isExcluded(dtpl: DocTemplateEntity) = { val qname = dtpl.qualifiedName - (qname.startsWith("scala.Tuple") || qname.startsWith("scala.Product") || qname.startsWith("scala.Function")) && - !(qname=="scala.Function1" || qname=="scala.Function2" || qname=="scala.Function" || - qname=="scala.Product1" || qname=="scala.Product2" || qname=="scala.Product" || - qname=="scala.Tuple1" || qname=="scala.Tuple2") + ( ( qname.startsWith("scala.Tuple") || qname.startsWith("scala.Product") || + qname.startsWith("scala.Function") || qname.startsWith("scala.runtime.AbstractFunction") + ) && !( + qname == "scala.Tuple1" || qname == "scala.Tuple2" || + qname == "scala.Product" || qname == "scala.Product1" || qname == "scala.Product2" || + qname == "scala.Function" || qname == "scala.Function1" || qname == "scala.Function2" || + qname == "scala.runtime.AbstractFunction0" || qname == "scala.runtime.AbstractFunction1" || + qname == "scala.runtime.AbstractFunction2" + ) + ) } def packageElem(pack: model.Package): NodeSeq = { 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 4a6a9de032..d90e3d2f64 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -71,6 +71,13 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
+ { if (constructors.isEmpty) NodeSeq.Empty else +
+

Instance constructors

+
    { constructors map (memberToHtml(_)) }
+
+ } + { if (typeMembers.isEmpty) NodeSeq.Empty else

Type Members

@@ -85,13 +92,6 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
} - { if (constructors.isEmpty) NodeSeq.Empty else -
-

Instance constructors

-
    { constructors map (memberToHtml(_)) }
-
- } -
@@ -114,146 +114,162 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { } mbr match { case dte: DocTemplateEntity if isSelf => -
{ memberToFullCommentHtml(mbr, isSelf) }
+ // comment of class itself +
{ memberToCommentBodyHtml(mbr, isSelf = true) }
case dte: DocTemplateEntity if mbr.comment.isDefined => + // comment of inner, documented class (only short comment, full comment is on the class' own page)

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

- case _ if mbr.comment.isDefined => -

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

-
{ useCaseCommentHtml }{ memberToFullCommentHtml(mbr, isSelf) }
- case _ => useCaseCommentHtml + case _ => + // comment of non-class member or non-documentented inner class + val commentBody = memberToCommentBodyHtml(mbr, isSelf = false) + if (commentBody.isEmpty) + NodeSeq.Empty + else { + + { if (mbr.comment.isEmpty) NodeSeq.Empty else { +

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

+ } + } +
{ useCaseCommentHtml }{ memberToCommentBodyHtml(mbr, isSelf) }
+
+ } } } - def memberToFullCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = - - { if (mbr.comment.isEmpty) NodeSeq.Empty else -
{ commentToHtml(mbr.comment) }
+ def memberToCommentBodyHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = + NodeSeq.Empty ++ + { if (mbr.comment.isEmpty) NodeSeq.Empty else +
{ commentToHtml(mbr.comment) }
+ } ++ + { val prs: List[ParameterEntity] = mbr match { + case cls: Class if cls.isCaseClass => + cls.typeParams ::: (cls.primaryConstructor map (_.valueParams.flatten)).toList.flatten + case trt: Trait => trt.typeParams + case dfe: Def => dfe.typeParams ::: dfe.valueParams.flatten + case ctr: Constructor => ctr.valueParams.flatten + case _ => Nil } - { val prs: List[ParameterEntity] = mbr match { - case cls: Class if cls.isCaseClass => - cls.typeParams ::: (cls.primaryConstructor map (_.valueParams.flatten)).toList.flatten - case trt: Trait => trt.typeParams - case dfe: Def => dfe.typeParams ::: dfe.valueParams.flatten - case ctr: Constructor => ctr.valueParams.flatten - case _ => Nil - } - def mbrCmt = mbr.comment.get - def paramCommentToHtml(prs: List[ParameterEntity]): NodeSeq = prs match { - case Nil => - NodeSeq.Empty - case (tp: TypeParam) :: rest => - val paramEntry: NodeSeq = { -
{ tp.name }
{ bodyToHtml(mbrCmt.typeParams(tp.name)) }
- } - paramEntry ++ paramCommentToHtml(rest) - case (vp: ValueParam) :: rest => - val paramEntry: NodeSeq = { -
{ vp.name }
{ bodyToHtml(mbrCmt.valueParams(vp.name)) }
- } - paramEntry ++ paramCommentToHtml(rest) - } - if (mbr.comment.isEmpty) NodeSeq.Empty - else { - val cmtedPrs = prs filter { - case tp: TypeParam => mbrCmt.typeParams isDefinedAt tp.name - case vp: ValueParam => mbrCmt.valueParams isDefinedAt vp.name + def mbrCmt = mbr.comment.get + def paramCommentToHtml(prs: List[ParameterEntity]): NodeSeq = prs match { + case Nil => + NodeSeq.Empty + case (tp: TypeParam) :: rest => + val paramEntry: NodeSeq = { +
{ tp.name }
{ bodyToHtml(mbrCmt.typeParams(tp.name)) }
} - if (cmtedPrs.isEmpty && mbrCmt.result.isEmpty) NodeSeq.Empty - else -
{ - paramCommentToHtml(cmtedPrs) ++ ( - mbrCmt.result match { - case None => NodeSeq.Empty - case Some(cmt) => -
returns
{ bodyToHtml(cmt) }
- }) - }
+ paramEntry ++ paramCommentToHtml(rest) + case (vp: ValueParam) :: rest => + val paramEntry: NodeSeq = { +
{ vp.name }
{ bodyToHtml(mbrCmt.valueParams(vp.name)) }
+ } + paramEntry ++ paramCommentToHtml(rest) + } + if (mbr.comment.isEmpty) NodeSeq.Empty + else { + val cmtedPrs = prs filter { + case tp: TypeParam => mbrCmt.typeParams isDefinedAt tp.name + case vp: ValueParam => mbrCmt.valueParams isDefinedAt vp.name } + if (cmtedPrs.isEmpty && mbrCmt.result.isEmpty) NodeSeq.Empty + else +
{ + paramCommentToHtml(cmtedPrs) ++ ( + mbrCmt.result match { + case None => NodeSeq.Empty + case Some(cmt) => +
returns
{ bodyToHtml(cmt) }
+ }) + }
} - { val fvs: List[comment.Paragraph] = visibility(mbr).toList ::: mbr.flags - if (fvs.isEmpty) NodeSeq.Empty else + } ++ + { val fvs: List[comment.Paragraph] = visibility(mbr).toList ::: mbr.flags + if (fvs.isEmpty) NodeSeq.Empty else +
+ attributes: { fvs map { fv => { inlineToHtml(fv.text) ++ xml.Text(" ") } } } +
+ } ++ + { tpl.companion match { + case Some(companion) if isSelf =>
- attributes: { fvs map { fv => { inlineToHtml(fv.text) ++ xml.Text(" ") } } } + go to: companion
+ case _ => + NodeSeq.Empty } - { tpl.companion match { - case Some(companion) if isSelf => -
- Go to: companion -
- case _ => - NodeSeq.Empty - } + } ++ + { val inDefTpls = mbr.inDefinitionTemplates + if (inDefTpls.tail.isEmpty && (inDefTpls.head == mbr.inTemplate)) NodeSeq.Empty else { +
+ definition classes: { templatesToHtml(inDefTpls, xml.Text(" → ")) } +
} - { val inDefTpls = mbr.inDefinitionTemplates - if (inDefTpls.tail.isEmpty && (inDefTpls.head == mbr.inTemplate)) NodeSeq.Empty else { + } ++ + { mbr match { + case dtpl: DocTemplateEntity if (isSelf && !dtpl.subClasses.isEmpty) =>
- definition classes: { templatesToHtml(inDefTpls, xml.Text(" → ")) } + known subclasses: { templatesToHtml(dtpl.subClasses, xml.Text(", ")) }
- } + case _ => NodeSeq.Empty } - { mbr match { - case dtpl: DocTemplateEntity if (isSelf && !dtpl.subClasses.isEmpty) => -
- known subclasses: { templatesToHtml(dtpl.subClasses, xml.Text(", ")) } -
- case _ => NodeSeq.Empty - } - } - { mbr match { - case dtpl: DocTemplateEntity if (isSelf && dtpl.sourceUrl.isDefined) => - val sourceUrl = tpl.sourceUrl.get - - case _ => NodeSeq.Empty - } + } ++ + { mbr match { + case dtpl: DocTemplateEntity if (isSelf && dtpl.sourceUrl.isDefined) => + val sourceUrl = tpl.sourceUrl.get + + case _ => NodeSeq.Empty } - { if(mbr.deprecation.isEmpty) NodeSeq.Empty else -
    deprecated: - {
  1. { bodyToHtml(mbr.deprecation.get) }
  2. } -
+ } ++ + { if (mbr.deprecation.isEmpty) NodeSeq.Empty else +
    deprecated: + {
  1. { bodyToHtml(mbr.deprecation.get) }
  2. } +
+ } ++ + { mbr.comment match { + case Some(comment) => + + { if(!comment.version.isEmpty) +
    version + { for(body <- comment.version.toList) yield
  1. {bodyToHtml(body)}
  2. } +
+ else NodeSeq.Empty + } + { if(!comment.since.isEmpty) +
    since + { for(body <- comment.since.toList) yield
  1. {bodyToHtml(body)}
  2. } +
+ else NodeSeq.Empty + } + { if(!comment.see.isEmpty) +
    see also: + { val seeXml:List[scala.xml.NodeSeq]=(for(see <- comment.see ) yield
  1. {bodyToHtml(see)}
  2. ) + seeXml.reduceLeft(_ ++ Text(", ") ++ _) + } +
+ else NodeSeq.Empty + } + { if(!comment.authors.isEmpty) +
    authors: + { val authorsXml:List[scala.xml.NodeSeq]=(for(author <- comment.authors ) yield
  1. {bodyToHtml(author)}
  2. ) + authorsXml.reduceLeft(_ ++ Text(", ") ++ _) + } +
+ else NodeSeq.Empty + } +
+ case None => NodeSeq.Empty } - { for(comment <- mbr.comment.toList) yield { - - { if(!comment.version.isEmpty) -
    version - { for(body <- comment.version.toList) yield
  1. {bodyToHtml(body)}
  2. } -
- else NodeSeq.Empty - } - { if(!comment.since.isEmpty) -
    since - { for(body <- comment.since.toList) yield
  1. {bodyToHtml(body)}
  2. } -
- else NodeSeq.Empty - } - { if(!comment.see.isEmpty) -
    see also: - { val seeXml:List[scala.xml.NodeSeq]=(for(see <- comment.see ) yield
  1. {bodyToHtml(see)}
  2. ) - seeXml.reduceLeft(_ ++ Text(", ") ++ _) - } -
- else NodeSeq.Empty - } - { if(!comment.authors.isEmpty) -
    authors: - { val authorsXml:List[scala.xml.NodeSeq]=(for(author <- comment.authors ) yield
  1. {bodyToHtml(author)}
  2. ) - authorsXml.reduceLeft(_ ++ Text(", ") ++ _) - } -
- else NodeSeq.Empty - } -
- }} -
+ } def kindToString(mbr: MemberEntity): String = mbr match { case tpl: DocTemplateEntity => if (tpl.isPackage) "package" else if (tpl.isClass) "class" else if (tpl.isTrait) "trait" else "object" case ctor: Constructor => "new" case tme: MemberEntity => - if (tme.isDef) "def" else if (tme.isVal) "val" else if (tme.isVar) "var" else "type" + val attr: String = if (tme.isImplicit) "implicit " else "" + val kind = if (tme.isDef) "def" else if (tme.isVal) "val" else if (tme.isVar) "var" else "type" + attr + kind } def boundsToHtml(hi: Option[TypeEntity], lo: Option[TypeEntity], hasLinks: Boolean): NodeSeq = { 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 a23c8b6402..5c8822b1c1 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 @@ -123,12 +123,12 @@ div.members > ol > li { text-align: right; float: left; display: inline-block; - width: 72px; + width: 7em; } .signature .symbol { display: inline; - padding-left: 8px; + padding-left: 0.7em; } .signature .name { @@ -219,12 +219,12 @@ div.members > ol > li { p.comment { display: block; - margin-left: 80px; + margin-left: 7.7em; } p.shortcomment { display: block; - margin-left: 80px; + margin-left: 7.7em; cursor: help; } @@ -234,7 +234,7 @@ div.fullcomment { } #template div.fullcomment { - margin: 6px 0 6px 80px; + margin: 6px 0 6px 7.7em; } div.fullcomment .block { diff --git a/src/compiler/scala/tools/nsc/doc/model/Entity.scala b/src/compiler/scala/tools/nsc/doc/model/Entity.scala index 7aa2c234ea..678702c7f1 100644 --- a/src/compiler/scala/tools/nsc/doc/model/Entity.scala +++ b/src/compiler/scala/tools/nsc/doc/model/Entity.scala @@ -49,6 +49,7 @@ trait MemberEntity extends Entity { def isDef: Boolean def isVal: Boolean def isVar: Boolean + def isImplicit: Boolean def isConstructor: Boolean def isAliasType: Boolean def isAbstractType: Boolean @@ -63,6 +64,7 @@ trait DocTemplateEntity extends TemplateEntity with MemberEntity { def sourceUrl: Option[java.net.URL] def typeParams: List[TypeParam] def parentType: Option[TypeEntity] + def parentTemplates: List[TemplateEntity] def linearization: List[TemplateEntity] def subClasses: List[DocTemplateEntity] def members: List[MemberEntity] diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 64dfbfb160..9641bc9045 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -52,6 +52,10 @@ class ModelFactory(val global: Global, val settings: doc.Settings) extends Comme def inTemplate = inTpl def toRoot: List[EntityImpl] = this :: inTpl.toRoot def qualifiedName = name + override def equals(that: Any) = that match { + case that: EntityImpl => this.sym == that.sym + case _ => false + } } /** Provides a default implementation for instances of the `WeakTemplateEntity` type. It must be instantiated as a @@ -121,6 +125,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) extends Comme def isDef = false def isVal = false def isVar = false + def isImplicit = sym.isImplicit def isConstructor = false def isAliasType = false def isAbstractType = false @@ -154,6 +159,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) extends Comme 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 = if (sym.isPackage) None else Some(makeType(RefinedType(sym.tpe.parents filter (_ != ScalaObjectClass.tpe), EmptyScope))) diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala index 0aff68ab02..dba538046a 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -45,8 +45,8 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => } } - protected val endOfText = '\u0003' - protected val endOfLine = '\u000A' + protected val endOfText = '\u0003' + protected val endOfLine = '\u000A' /** Something that should not have happened, happened, and Scaladoc should exit. */ protected def oops(msg: String): Nothing = @@ -56,6 +56,22 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => protected val CleanCommentLine = new Regex("""(?:\s*\*\s?)?(.*)""") + /** Dangerous HTML tags that should be replaced by something safer, such as wiki syntax, or that should be dropped. */ + protected val DangerousHtml = + new Regex("""<(/?(?:p|div|pre|ol|ul|li|h[1-6]|code))[^>]*>""") + + /** Maps a dangerous HTML tag to a safe wiki replacement, or an empty string if it cannot be salvaged. */ + protected def htmlReplacement(mtch: Regex.Match): String = mtch.matched match { + case "p" | "div" => "\n\n" + case "h1" | "h2" | "h3" | "h4" | "h5" | "h6" => "\n= " + case "/h1" | "/h2" | "/h3" | "/h4" | "/h5" | "/h6" => " =\n" + case "pre" => "{{{" + case "/pre" => "}}}" + case "code" | "/code" => "`" + case "li" => "\n - " + case _ => "" + } + /** A Scaladoc tag not linked to a symbol. Returns the name of the tag, and the rest of the line. */ protected val SimpleTag = new Regex("""\s*@(\S+)\s+(.*)""") @@ -99,7 +115,9 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => tl } } - comment.trim.stripPrefix("/*").stripSuffix("*/").lines.toList map (cleanLine(_)) + val strippedComment = comment.trim.stripPrefix("/*").stripSuffix("*/") + val safeComment = DangerousHtml.replaceAllIn(strippedComment, { htmlReplacement(_) }) + safeComment.lines.toList map (cleanLine(_)) } /** Parses a comment (in the form of a list of lines) to a Comment instance, recursively on lines. To do so, it diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index c0b54cb4f0..c8d3308077 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -802,6 +802,14 @@ trait Infer { (argtpes1, argPos, namesOK) } + /** don't do a () to (()) conversion for methods whose second parameter + * is a varargs. This is a fairly kludgey way to address #3224. + * We'll probably find a better way to do this by identifying + * tupled and n-ary methods, but thiws is something for a future major revision. + */ + def isUnitForVarArgs(args: List[AnyRef], params: List[Symbol]): Boolean = + args.length == 0 && params.length == 2 && isVarArgs(params) + /** Is there an instantiation of free type variables undetparams * such that function type ftpe is applicable to * argtpes and its result conform to pt? @@ -833,14 +841,15 @@ trait Infer { def tryTupleApply: Boolean = { // if 1 formal, 1 argtpe (a tuple), otherwise unmodified argtpes0 - val tupleArgTpe = actualTypes(argtpes0 map { + val tupleArgTpes = actualTypes(argtpes0 map { // no assignment is treated as named argument here case NamedType(name, tp) => UnitClass.tpe case tp => tp }, formals.length) - argtpes0.length != tupleArgTpe.length && - isApplicable(undetparams, ftpe, tupleArgTpe, pt) + argtpes0.length != tupleArgTpes.length && + !isUnitForVarArgs(argtpes0, params) && + isApplicable(undetparams, ftpe, tupleArgTpes, pt) } def typesCompatible(argtpes: List[Type]) = { val restpe = ftpe.resultType(argtpes) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 284b12e501..3fe937f241 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2327,12 +2327,14 @@ trait Typers { self: Analyzer => // if 1 formal, 1 arg (a tuple), otherwise unmodified args val tupleArgs = actualArgs(tree.pos.makeTransparent, args, formals.length) - if (tupleArgs.length != args.length) { + if (tupleArgs.length != args.length && !isUnitForVarArgs(args, params)) { // expected one argument, but got 0 or >1 ==> try applying to tuple // the inner "doTypedApply" does "extractUndetparams" => restore when it fails val savedUndetparams = context.undetparams silent(_.doTypedApply(tree, fun, tupleArgs, mode, pt)) match { - case t: Tree => Some(t) + case t: Tree => +// println("tuple conversion to "+t+" for "+mt)//DEBUG + Some(t) case ex => context.undetparams = savedUndetparams None diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index a60721f0ca..5ba52f5f06 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -134,9 +134,9 @@ trait Unapplies extends ast.TreeDSL /** The module corresponding to a case class; without any member definitions */ def caseModuleDef(cdef: ClassDef): ModuleDef = { - def inheritFromFun1 = !(cdef.mods hasFlag ABSTRACT) && cdef.tparams.isEmpty && constrParamss(cdef).length == 1 - def createFun1 = gen.scalaFunctionConstr(constrParamss(cdef).head map (_.tpt), toIdent(cdef)) - def parents = if (inheritFromFun1) List(createFun1) else Nil + def inheritFromFun = !(cdef.mods hasFlag ABSTRACT) && cdef.tparams.isEmpty && constrParamss(cdef).length == 1 + def createFun = gen.scalaFunctionConstr(constrParamss(cdef).head map (_.tpt), toIdent(cdef)) + def parents = if (inheritFromFun) List(createFun) else Nil companionModuleDef(cdef, parents ::: List(gen.scalaScalaObjectConstr)) } diff --git a/src/library/scala/native.scala b/src/library/scala/native.scala index fbacf43b72..8aeffe1632 100644 --- a/src/library/scala/native.scala +++ b/src/library/scala/native.scala @@ -11,16 +11,14 @@ package scala -/** - * Marker for native methods. - *

- * @native def f(x: Int, y: List[Long]): String = .. - *

- *

- * Method body is not generated if method is marked with @native, - * but it is type checked when present. - *

- * - * @since 2.6 - */ +/** Marker for native methods. + * + * {{{ + * @native def f(x: Int, y: List[Long]): String = ... + * }}} + * + * Method body is not generated if method is marked with `@native`, + * but it is type checked when present. + * + * @since 2.6 */ class native extends StaticAnnotation {} diff --git a/src/partest/scala/tools/partest/Actions.scala b/src/partest/scala/tools/partest/Actions.scala index 48b80cface..15351db2a7 100644 --- a/src/partest/scala/tools/partest/Actions.scala +++ b/src/partest/scala/tools/partest/Actions.scala @@ -54,7 +54,7 @@ trait Actions { proc = Process.exec(toArgs(cmd), execEnv, execCwd.orNull, true) proc.slurp() } - proc.waitFor() == 0 + proc != null && (proc.waitFor() == 0) } result getOrElse { warning("Process never terminated: '%s'" format cmd) diff --git a/src/partest/scala/tools/partest/Compilable.scala b/src/partest/scala/tools/partest/Compilable.scala index c11532f278..d7365c1620 100644 --- a/src/partest/scala/tools/partest/Compilable.scala +++ b/src/partest/scala/tools/partest/Compilable.scala @@ -81,7 +81,10 @@ trait PartestCompilation { class PartestGlobal(settings: Settings, val creporter: ConsoleReporter) extends Global(settings, creporter) { def partestCompile(files: List[String], printSummary: Boolean): Boolean = { try { new Run compile files } - catch { case FatalError(msg) => creporter.error(null, "fatal error: " + msg) } + catch { + case FatalError(msg) => creporter.error(null, "fatal error: " + msg) + case ae: AssertionError => creporter.error(null, ""+ae) + } if (printSummary) creporter.printSummary @@ -102,4 +105,4 @@ trait PartestCompilation { (new PartestGlobal(command.settings, reporter), command.files) } } -} \ No newline at end of file +} diff --git a/src/partest/scala/tools/partest/Dispatcher.scala b/src/partest/scala/tools/partest/Dispatcher.scala index 2c7d9d6a2f..2a9d99ab60 100644 --- a/src/partest/scala/tools/partest/Dispatcher.scala +++ b/src/partest/scala/tools/partest/Dispatcher.scala @@ -31,14 +31,14 @@ trait Dispatcher { val groups = selected groupBy (_.category) val count = selected.size - if (count == 0) return CombinedTestResults(0, 0, 0) + if (count == 0) return CombinedTestResults(0, 0, 0, Nil) else if (count == allTests.size) verbose("Running all %d tests." format count) else verbose("Running %d/%d tests: %s".format(count, allTests.size, toStringTrunc(selected map (_.label) mkString ", "))) allCategories collect { case x if groups contains x => runCategory(x, groups(x)) } reduceLeft (_ ++ _) } - private def parallelizeTests(tests: List[TestEntity]): immutable.Map[TestEntity, Int] = { + private def parallelizeTests(tests: List[TestEntity]): immutable.Map[TestEntity, TestResult] = { // propagate verbosity if (isDebug) scala.actors.Debug.level = 3 @@ -63,9 +63,9 @@ trait Dispatcher { case ResultsOfRun(resultMap) => resultMap case TIMEOUT => warning("Worker %d timed out." format w.workerNum) - immutable.Map[TestEntity, Int]() // mark all the worker's tests as having timed out - should be hard to miss - groups(w.workerNum) map (_ -> 2) toMap + // immutable.Map[TestEntity, TestResult]() + groups(w.workerNum) map (x => (x -> new Timeout(x))) toMap } }) reduceLeft (_ ++ _) } @@ -75,9 +75,10 @@ trait Dispatcher { normal("%s (%s tests in %s)\n".format(category.startMessage, tests.size, category)) val (milliSeconds, resultMap) = timed2(parallelizeTests(tests)) - val (passed, failed) = resultsToStatistics(resultMap) + val (passed, failed) = resultsToStatistics(resultMap mapValues (_.state)) + val failures = resultMap.values filterNot (_.passed) toList - CombinedTestResults(passed, failed, milliSeconds) + CombinedTestResults(passed, failed, milliSeconds, failures) } /** A Worker is given a bundle of tests and runs them all sequentially. @@ -92,8 +93,8 @@ trait Dispatcher { /** Runs the tests. Passes the result Map to onCompletion when done. */ - private def runTests(tests: List[TestEntity])(onCompletion: immutable.Map[TestEntity, Int] => Unit) { - var results = new immutable.HashMap[TestEntity, Int] // maps tests to results + private def runTests(tests: List[TestEntity])(onCompletion: immutable.Map[TestEntity, TestResult] => Unit) { + var results = new immutable.HashMap[TestEntity, TestResult] // maps tests to results val numberOfTests = tests.size val testIterator = tests.iterator def processed = results.size @@ -122,7 +123,7 @@ trait Dispatcher { return warning("Received duplicate result for %s: was %s, now %s".format(test, results(test), state)) // increment the counter for this result state - results += (test -> state) + results += (test -> result) // show on screen if (isDryRun) normal("\n") // blank line between dry run traces diff --git a/src/partest/scala/tools/partest/Results.scala b/src/partest/scala/tools/partest/Results.scala index 4e0c446788..8078e7bf85 100644 --- a/src/partest/scala/tools/partest/Results.scala +++ b/src/partest/scala/tools/partest/Results.scala @@ -16,7 +16,7 @@ trait Results { /** The response from a Worker who has been given TestsToRun. */ - case class ResultsOfRun(results: immutable.Map[TestEntity, Int]) + case class ResultsOfRun(results: immutable.Map[TestEntity, TestResult]) /** The result of a single test. (0: OK, 1: FAILED, 2: TIMEOUT) */ @@ -39,7 +39,7 @@ trait Results { case _ => false } override def hashCode = entity.hashCode - override def toString = "%s (%s)".format(entity, if (passed) "passed" else "failed") + override def toString = "%s [%s]".format(entity, description) } class Success(val entity: TestEntity) extends TestResult(0, " OK ") { @@ -58,6 +58,7 @@ trait Results { if (isShowLog || isTrace) normal(toStringTrunc(entity.failureMessage(), 1600)) } + override def toString = List(super.toString, toStringTrunc(entity.failureMessage(), 400)) mkString "\n" } class Timeout(val entity: TestEntity) extends TestResult(2, "TIME OUT") { def colorize(s: String) = markFailure(s) @@ -84,7 +85,8 @@ trait Results { case class CombinedTestResults( passed: Int, failed: Int, - elapsedMilliseconds: Long + elapsedMilliseconds: Long, + failures: List[TestResult] ) { // housekeeping val elapsedSecs = elapsedMilliseconds / 1000 @@ -100,14 +102,20 @@ trait Results { def ++(x: CombinedTestResults) = CombinedTestResults( passed + x.passed, failed + x.failed, - elapsedMilliseconds + x.elapsedMilliseconds + elapsedMilliseconds + x.elapsedMilliseconds, + failures ::: x.failures ) - def elapsedString = "%02d:%02d:%02d".format(elapsedHrs, dispMins, dispSecs) + def elapsedString = "%02d:%02d:%02d".format(elapsedHrs, dispMins, dispSecs) + def failuresString = { + if (failures.isEmpty) "" + else "Summary of failures:" :: failures mkString ("\n", "\n", "") + } + override def toString = if (total == 0) "There were no tests to run." else if (isDryRun) "%d tests would be run." format total - else if (hasFailures) "%d of %d tests failed (elapsed time: %s)".format(failed, total, elapsedString) + else if (hasFailures) "%d of %d tests failed (elapsed time: %s)".format(failed, total, elapsedString) + failuresString else "All %d tests were successful (elapsed time: %s)".format(total, elapsedString) } } \ No newline at end of file diff --git a/src/partest/scala/tools/partest/io/Logging.scala b/src/partest/scala/tools/partest/io/Logging.scala index 3d1b0fa0b4..3667faaf3d 100644 --- a/src/partest/scala/tools/partest/io/Logging.scala +++ b/src/partest/scala/tools/partest/io/Logging.scala @@ -75,8 +75,9 @@ trait Logging { def loggingResult(body: => String) = try returning(true)(_ => logFile writeAll body) catch { - case x: ControlThrowable => throw x - case x: Throwable => logException(x) + case x: ControlThrowable => throw x + case x: InterruptedException => normal(this + " received interrupt, failing.\n") ; false + case x: Throwable => logException(x) } def throwableToString(x: Throwable): String = { diff --git a/test/files/jvm/actor-uncaught-exception2.check b/test/files/jvm/actor-uncaught-exception2.check new file mode 100644 index 0000000000..870a5d32f9 --- /dev/null +++ b/test/files/jvm/actor-uncaught-exception2.check @@ -0,0 +1,2 @@ +UncaughtException(StartError,None,None,MyException: I don't want to run!) +UncaughtException(MessageError,Some('ping),Some(Supervisor),MyException: No message for me!) diff --git a/test/files/jvm/actor-uncaught-exception2.scala b/test/files/jvm/actor-uncaught-exception2.scala new file mode 100644 index 0000000000..973cfb370a --- /dev/null +++ b/test/files/jvm/actor-uncaught-exception2.scala @@ -0,0 +1,48 @@ +import scala.actors.{Actor, Exit, Debug} + +class MyException(msg: String) extends Exception(msg) { + override def fillInStackTrace() = this +} + +object Test { + + case object StartError extends Actor { + def act() { + throw new MyException("I don't want to run!") + } + } + + case object MessageError extends Actor { + def act() { + react { + case _ => throw new MyException("No message for me!") + } + } + } + + case object Supervisor extends Actor { + def act() { + trapExit = true + link(StartError) + link(MessageError) + StartError.start() + MessageError.start() + + Actor.loop { + react { + case Exit(actor, reason) => + println(reason) + if (actor == StartError) + MessageError ! 'ping + else + exit() + } + } + } + } + + def main(args: Array[String]) { + Debug.level = 1 // decrease level so that it does not print warnings + Supervisor.start() + } +} diff --git a/test/files/neg/t3224.check b/test/files/neg/t3224.check new file mode 100644 index 0000000000..29304c567a --- /dev/null +++ b/test/files/neg/t3224.check @@ -0,0 +1,6 @@ +t3224.scala:29: error: polymorphic expression cannot be instantiated to expected type; + found : [T]Array[T] + required: List[?] + println(Texts textL Array()); println(Texts textL Array(1)); println(Texts textL Array(1, 1)) + ^ +one error found diff --git a/test/files/neg/t3224.scala b/test/files/neg/t3224.scala new file mode 100755 index 0000000000..0e24baf28a --- /dev/null +++ b/test/files/neg/t3224.scala @@ -0,0 +1,30 @@ +object Texts{ + def textL[T](list: List[T]) = { + list match{ + case List() => "Empty" + case List(_) => "One" + case List(_*) => "Many" + } + } + + def textA[T](array: Array[T]) = { + array match{ + case Array() => "Empty" + case Array(_) => "One" + case Array(_*) => "Many" + } + } +} + +object Test extends Application { + + implicit def array2list[T](array: Array[T]) = { + println(array.toList.size) + array.toList + } + + + println(Texts textL List()); println(Texts textL List(1)); println(Texts textL List(1, 1)); + + println(Texts textL Array()); println(Texts textL Array(1)); println(Texts textL Array(1, 1)) +} -- cgit v1.2.3