From 34fe33a61291ec51cb0598b3702b2c6de8ebb3f2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 7 Apr 2008 15:57:07 +0000 Subject: (1) Removed generation of $tag method for inter... (1) Removed generation of $tag method for interfaces (2) improved type inference for clsoures (3) redesign of CharSequence and regex. --- .../scala/tools/nsc/ast/parser/Parsers.scala | 12 +- .../scala/tools/nsc/typechecker/Contexts.scala | 3 +- .../scala/tools/nsc/typechecker/EtaExpansion.scala | 13 ++ .../scala/tools/nsc/typechecker/Infer.scala | 4 +- .../scala/tools/nsc/typechecker/Typers.scala | 66 +++++- .../scala/tools/nsc/typechecker/Unapplies.scala | 2 +- src/library/scala/Predef.scala | 8 +- src/library/scala/Seq.scala | 12 +- src/library/scala/StringBuilder.scala | 7 + .../scala/collection/immutable/PagedSeq.scala | 245 +++++++++++++++++++++ src/library/scala/runtime/RichString.scala | 9 +- .../util/parsing/combinator/RegexParsers.scala | 29 ++- .../scala/util/parsing/input/CharArrayReader.scala | 2 +- .../util/parsing/input/CharSequenceReader.scala | 10 +- .../scala/util/parsing/input/PagedSeqReader.scala | 71 ++++++ src/library/scala/util/parsing/input/Reader.scala | 15 +- .../scala/util/parsing/input/StreamReader.scala | 43 ++-- test/files/neg/bug414.check | 2 +- test/files/run/caseclasses.scala | 9 + 19 files changed, 492 insertions(+), 70 deletions(-) create mode 100755 src/library/scala/collection/immutable/PagedSeq.scala create mode 100755 src/library/scala/util/parsing/input/PagedSeqReader.scala diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index fd1db30e74..e7c33cc426 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2200,9 +2200,7 @@ trait Parsers extends NewScanners with MarkupParsers { template, template.parents, makeSelfDef(nme.WILDCARD, thistpe), template.body) } else syntaxError("`requires' cannot be combined with explicit self type", false) } - val mods1 = if (mods.hasFlag(Flags.TRAIT) && - (template.body forall treeInfo.isInterfaceMember)) - mods | Flags.INTERFACE + val mods1 = if (isInterface(mods, template.body)) mods | Flags.INTERFACE else mods val result = ClassDef(mods1, name, tparams, template) implicitClassViews = savedViews @@ -2271,6 +2269,9 @@ trait Parsers extends NewScanners with MarkupParsers { } } + def isInterface(mods: Modifiers, body: List[Tree]) = + (mods.hasFlag(Flags.TRAIT) && (body forall treeInfo.isInterfaceMember)) + /** ClassTemplateOpt ::= extends ClassTemplate | [[extends] TemplateBody] * TraitTemplateOpt ::= extends TraitTemplate | [[extends] TemplateBody] */ @@ -2286,7 +2287,10 @@ trait Parsers extends NewScanners with MarkupParsers { (List(), List(List()), self, body) } var parents = parents0 - if (name != nme.ScalaObject.toTypeName) parents = parents ::: List(scalaScalaObjectConstr) + if (name != nme.ScalaObject.toTypeName && !isInterface(mods, body)) + parents = parents ::: List(scalaScalaObjectConstr) + if (parents.isEmpty) + parents = List(scalaAnyRefConstr) if (mods.hasFlag(Flags.CASE)) parents = parents ::: List(productConstr) val tree = Template(parents, self, constrMods, vparamss, argss, body) // @S: if nothing parsed, don't use next position! diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 758a006e0e..d0e90a2fe2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -110,7 +110,8 @@ trait Contexts { self: Analyzer => var checking = false var retyping = false - var savedTypeBounds: List[(Symbol, Type)] = List() + var savedTypeBounds: List[(Symbol, Type)] = List() // saved type bounds + // for type parameters which are narrowed in a GADT def intern0 : Context = { if (this eq NoContext) return this diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala index 7b705036ac..1c6412419d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala +++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala @@ -19,6 +19,19 @@ trait EtaExpansion { self: Analyzer => import global._ import posAssigner.atPos + object etaExpansion { + def unapply(tree: Tree): Option[(List[ValDef], Tree, List[Tree])] = tree match { + case Function(vparams, Apply(fn, args)) + if (List.forall2(vparams, args) { + case (vparam, Ident(name)) => vparam.name == name + case _ => false + }) => + Some((vparams, fn, args)) + case _ => + None + } + } + /**

* Expand partial function applications of type type. *

diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 1223328c96..c118df8a54 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -1150,7 +1150,7 @@ trait Infer {
           val ptvars = ptparams map freshVar
           val pt1 = pt.instantiateTypeParams(ptparams, ptvars)
           if (!isPopulated(tp, pt1)) {
-            error(pos, "pattern type is incompatibe with expected type"+foundReqMsg(pattp, pt))
+            error(pos, "pattern type is incompatible with expected type"+foundReqMsg(pattp, pt))
             return pattp
           }
           ptvars foreach instantiateTypeVar
@@ -1169,7 +1169,7 @@ trait Infer {
         if (pat.tpe <:< pt1)
           ptvars foreach instantiateTypeVar
         else
-          error(pat.pos, "pattern type is incompatibe with expected type"+foundReqMsg(pat.tpe, pt))
+          error(pat.pos, "pattern type is incompatible with expected type"+foundReqMsg(pat.tpe, pt))
       }
 
     object toOrigin extends TypeMap {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 12e0e63960..2cdbb3d57d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1449,10 +1449,22 @@ trait Typers { self: Analyzer =>
         errorTree(fun, "wrong number of parameters; expected = " + argpts.length)
       else {
         val vparamSyms = List.map2(fun.vparams, argpts) { (vparam, argpt) =>
-          if (vparam.tpt.isEmpty)
+          if (vparam.tpt.isEmpty) {
             vparam.tpt.tpe =
               if (isFullyDefined(argpt)) argpt
               else {
+                fun match {
+                  case etaExpansion(vparams, fn, args) if !codeExpected =>
+                    println("typing eta "+fn)
+                    silent(_.typed(fn, funMode(mode), pt)) match {
+                      case fn1: Tree =>
+                        val ftpe = normalize(fn1.tpe) baseType FunctionClass(fun.vparams.length)
+                        if (isFunctionType(ftpe) && isFullyDefined(ftpe))
+                          return typedFunction(fun, mode, ftpe)
+                      case _ =>
+                    }
+                  case _ =>
+                }
                 error(
                   vparam.pos,
                   "missing parameter type"+
@@ -1460,6 +1472,7 @@ trait Typers { self: Analyzer =>
                    else ""))
                 ErrorType
               }
+          }
           enterSym(context, vparam)
           if (context.retyping) context.scope enter vparam.symbol
           vparam.symbol
@@ -1593,6 +1606,31 @@ trait Typers { self: Analyzer =>
       }
     }
 
+    /** Does function need to be instantiated, because a missing parameter
+     *  in an argument closure overlaps with an uninstantiated formal?
+     */
+    def needsInstantiation(tparams: List[Symbol], formals: List[Type], args: List[Tree]) = {
+      def isLowerBounded(tparam: Symbol) = {
+        val losym = tparam.info.bounds.lo.typeSymbol
+        losym != AllClass && losym != AllRefClass
+      }
+      List.exists2(formals, args) {
+        case (formal, Function(vparams, _)) =>
+          (vparams exists (_.tpt.isEmpty)) &&
+          vparams.length <= MaxFunctionArity &&
+          (formal baseType FunctionClass(vparams.length) match {
+            case TypeRef(_, _, formalargs) =>
+              List.exists2(formalargs, vparams) ((formalarg, vparam) =>
+                vparam.tpt.isEmpty && (tparams exists (formalarg contains))) &&
+              (tparams forall isLowerBounded)
+            case _ =>
+              false
+          })
+        case _ =>
+          false
+      }
+    }
+
     /**
      *  @param tree ...
      *  @param fun0 ...
@@ -1604,12 +1642,19 @@ trait Typers { self: Analyzer =>
     def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Int, pt: Type): Tree = {
       var fun = fun0
       if (fun.hasSymbol && (fun.symbol hasFlag OVERLOADED)) {
-        // preadapt symbol to number of arguments given
-        val argtypes = args map (arg => AllClass.tpe)
+        // preadapt symbol to number and shape of arguments given
+        def shapeType(arg: Tree): Type = arg match {
+          case Function(vparams, body) =>
+            functionType(vparams map (vparam => AnyClass.tpe), shapeType(body))
+          case _ =>
+            AllClass.tpe
+        }
+        val argtypes = args map shapeType
         val pre = fun.symbol.tpe.prefix
         var sym = fun.symbol filter { alt =>
           isApplicableSafe(context.undetparams, followApply(pre.memberType(alt)), argtypes, pt)
         }
+        //println("narrowed to "+sym+":"+sym.info+"/"+argtypes)
         if (sym hasFlag OVERLOADED) {
           // eliminate functions that would result from tupling transforms
           val sym1 = sym filter (alt => hasExactlyNumParams(followApply(alt.tpe), argtypes.length))
@@ -1673,6 +1718,10 @@ trait Typers { self: Analyzer =>
                 atPos(tree.pos) { gen.mkNil setType restpe }
               } else
                 constfold(copy.Apply(tree, fun, args2).setType(ifPatternSkipFormals(restpe)))
+            } else if (needsInstantiation(tparams, formals, args1)) {
+              //println("needs inst "+fun+" "+tparams+"/"+(tparams map (_.info)))
+              inferExprInstance(fun, tparams, WildcardType)
+              doTypedApply(tree, fun, args1, mode, pt)
             } else {
               assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns
               val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt)
@@ -3527,9 +3576,14 @@ trait Typers { self: Analyzer =>
           List()
       }
 
-      def implicitManifest(pt: Type): Tree = pt match {
-        case TypeRef(_, ManifestClass, List(arg)) => manifestOfType(pos, arg)
-        case _ => EmptyTree
+      def implicitManifest(pt: Type): Tree = {
+        // test below is designed so that ManifestClass need not be loaded
+        // (because it's not available everywhere)
+        if (pt.typeSymbol.fullNameString == "scala.reflect.Manifest")
+          pt match {
+            case TypeRef(_, ManifestClass, List(arg)) => manifestOfType(pos, arg)
+          }
+        else EmptyTree
       }
 
       var tree = searchImplicit(context.implicitss, true)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index f2247f813c..e077329d4c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -135,7 +135,7 @@ trait Unapplies { self: Analyzer =>
    */
   def caseModuleDef(cdef: ClassDef): ModuleDef = atPos(cdef.pos) {
     var parents = List(gen.scalaScalaObjectConstr)
-    if (cdef.tparams.isEmpty && constrParams(cdef).length == 1)
+    if (!(cdef.mods hasFlag ABSTRACT) && cdef.tparams.isEmpty && constrParams(cdef).length == 1)
       parents = gen.scalaFunctionConstr(constrParams(cdef).head map (_.tpt),
                                         Ident(cdef.name)) :: parents
     ModuleDef(
diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala
index c7a01d6642..387f5c92d3 100644
--- a/src/library/scala/Predef.scala
+++ b/src/library/scala/Predef.scala
@@ -344,6 +344,12 @@ object Predef {
   implicit def forceRandomAccessCharSeq(x: runtime.RichString): String = x.mkString
   implicit def lazyStreamToConsable[A](xs: => Stream[A]) = new runtime.StreamCons(xs)
 
-  def currentThread = java.lang.Thread.currentThread()
+  implicit def seqToCharSequence(xs: RandomAccessSeq[Char]): CharSequence = new CharSequence {
+    def length: Int = xs.length
+    def charAt(index: Int): Char = xs(index)
+    def subSequence(start: Int, end: Int): CharSequence = seqToCharSequence(xs.slice(start, end))
+    override def toString: String = xs.mkString("")
+  }
 
+  def currentThread = java.lang.Thread.currentThread()
 }
diff --git a/src/library/scala/Seq.scala b/src/library/scala/Seq.scala
index bc075fb745..6b545ae6e7 100644
--- a/src/library/scala/Seq.scala
+++ b/src/library/scala/Seq.scala
@@ -313,8 +313,8 @@ trait Seq[+A] extends AnyRef with PartialFunction[Int, A] with Collection[A] {
     result.toList
   }
 
-   /** A sub-sequence of len elements
-    *  starting at index from (non-strict)
+   /** A sub-sequence starting at index from
+    *  and ending (non-inclusive) at index until (non-strict)
     *
     *  @param from   The index of the first element of the slice
     *  @param until    The index of the element following the slice
@@ -323,6 +323,14 @@ trait Seq[+A] extends AnyRef with PartialFunction[Int, A] with Collection[A] {
     */
   def slice(from: Int, until: Int): Seq[A] = drop(from).take(until - from)
 
+   /** A sub-sequence starting at index from
+    *  and extending up to the length of the current sequence (non-strict)
+    *
+    *  @param from   The index of the first element of the slice
+    *  @throws IndexOutOfBoundsException if from < 0
+    */
+  def slice(from: Int): Seq[A] = slice(from, length)
+
   /** Returns the longest prefix of this sequence whose elements satisfy
    *  the predicate p.
    *
diff --git a/src/library/scala/StringBuilder.scala b/src/library/scala/StringBuilder.scala
index 92ee3b9ac8..f6da576b07 100644
--- a/src/library/scala/StringBuilder.scala
+++ b/src/library/scala/StringBuilder.scala
@@ -943,4 +943,11 @@ object StringBuilder {
     }
     -1
   }
+
+  implicit def toCharSequence(sb: StringBuilder): java.lang.CharSequence = new java.lang.CharSequence {
+    def length: Int = sb.length
+    def charAt(index: Int): Char = sb.charAt(index)
+    def subSequence(start: Int, end: Int): java.lang.CharSequence = sb.substring(start, end)
+    override def toString: String = sb.toString
+  }
 }
diff --git a/src/library/scala/collection/immutable/PagedSeq.scala b/src/library/scala/collection/immutable/PagedSeq.scala
new file mode 100755
index 0000000000..de034e67dd
--- /dev/null
+++ b/src/library/scala/collection/immutable/PagedSeq.scala
@@ -0,0 +1,245 @@
+/*                     __                                               *\
+**     ________ ___   / /  ___     Scala API                            **
+**    / __/ __// _ | / /  / _ |    (c) 2006-2007, LAMP/EPFL             **
+**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
+** /____/\___/_/ |_/____/_/ | |                                         **
+**                          |/                                          **
+\*                                                                      */
+
+// $Id: PagedSeq.scala 14497 2008-04-04 12:09:06Z washburn $
+
+
+package scala.collection.immutable
+
+import java.io._
+import util.matching.Regex
+
+
+/** The PagedSeq object defines a lazy implementations of
+ *  a random access sequence.
+ */
+object PagedSeq {
+  final val UndeterminedEnd = Math.MAX_INT
+
+  /** Constructs a character sequence from a character iterator */
+  def fromIterator[T](source: Iterator[T]): PagedSeq[T] =
+    new PagedSeq[T]((data: Array[T], start: Int, len: Int) => {
+      var i = 0
+      while (i < len && source.hasNext) {
+        data(start + i) = source.next
+        i += 1
+      }
+      if (i == 0) -1 else i
+    })
+
+  /** Constructs a character sequence from a character iterable */
+  def fromIterable[T](source: Iterable[T]): PagedSeq[T] =
+    fromIterator(source.elements)
+
+  /** Constructs a character sequence from a string iterator */
+  def fromStrings(source: Iterator[String]): PagedSeq[Char] = {
+    var current: String = ""
+    def more(data: Array[Char], start: Int, len: Int): Int =
+      if (current.length != 0) {
+        val cnt = current.length min len
+        current.getChars(0, cnt, data, start)
+        current = current.substring(cnt)
+        if (cnt == len) cnt
+        else (more(data, start + cnt, len - cnt) max 0) + cnt
+      } else if (source.hasNext) {
+        current = source.next
+        more(data, start, len)
+      } else -1
+    new PagedSeq(more(_: Array[Char], _: Int, _: Int))
+  }
+
+  /** Constructs a character sequence from a string iterable */
+  def fromStrings(source: Iterable[String]): PagedSeq[Char] =
+    fromStrings(source.elements)
+
+  /** Constructs a character sequence from a line iterator
+   *  Lines do not contain trailing `\n' characters; The method inserts
+   *  a line separator `\n' between any two lines in the sequence.
+   */
+  def fromLines(source: Iterator[String]): PagedSeq[Char] = {
+    var isFirst = true
+    fromStrings(source map { line =>
+      if (isFirst) line
+      else {
+        isFirst = false
+        "\n"+line
+      }
+    })
+  }
+
+  /** Constructs a character sequence from a line iterable
+   *  Lines do not contain trailing `\n' characters; The method inserts
+   *  a line separator `\n' between any two lines in the sequence.
+   */
+  def fromLines(source: Iterable[String]): PagedSeq[Char] =
+    fromLines(source.elements)
+
+  /** Constructs a character sequence from an input reader
+   */
+  def fromReader(source: Reader): PagedSeq[Char] =
+    new PagedSeq(source.read(_: Array[Char], _: Int, _: Int))
+
+  /** Constructs a character sequence from an input file
+   */
+  def fromFile(source: File): PagedSeq[Char] =
+    fromReader(new FileReader(source))
+
+  /** Constructs a character sequence from a file with given name
+   */
+  def fromFile(source: String): PagedSeq[Char] =
+    fromFile(new File(source))
+
+  /** Constructs a character sequence from a scala.io.Source value
+   */
+  def fromSource(source: io.Source) =
+    fromLines(source.getLines)
+}
+
+
+import PagedSeq._
+
+/** An implementation of lazily computed sequences, where elements are stored
+ *  in ``pages'', i.e. arrays of fixed size.
+ *
+ * @author Martin Odersky
+ */
+class PagedSeq[T] protected (more: (Array[T], Int, Int) => Int,
+                             first: Page[T], start: Int, end: Int) extends RandomAccessSeq[T] {
+
+  /**  A paged sequence is constructed from a method that produces more characters when asked.
+   *  The producer method is analogous to the read method in java.io.Reader.
+   *  It takes three parameters: an array of characters, a start index, and an end index.
+   *  It should try to fill the array between start and end indices (not including end index).
+   *  It returns the number of characters produced, or -1 if end of logical input stream was reached
+   *  before any character was read.
+   */
+  def this(more: (Array[T], Int, Int) => Int) = this(more, new Page[T](0), 0, UndeterminedEnd)
+
+  private var current: Page[T] = first
+
+  private def latest = first.latest
+
+  private def addMore() = latest.addMore(more)
+
+  private def page(absindex: Int) = {
+    if (absindex < current.start)
+      current = first
+    while (absindex >= current.end && current.next != null)
+      current = current.next
+    while (absindex >= current.end && !current.isLast) {
+      current = addMore()
+    }
+    current
+  }
+
+  /** The length of the character sequence
+   *  Note: calling this method will force sequence to be read until the end.
+   */
+  def length: Int = {
+    while (!latest.isLast) addMore()
+    (latest.end min end) - start
+  }
+
+  /** The character at position `index'.
+   */
+  def apply(index: Int) =
+    if (isDefinedAt(index)) page(index + start)(index + start)
+    else throw new IndexOutOfBoundsException(index.toString)
+
+  /** Is character sequence defined at `index'?
+   *  Unlike `length' this operation does not force reading
+   *  a lazy sequence to the end.
+   */
+  override def isDefinedAt(index: Int) =
+    index >= 0 && index < end - start && {
+      val p = page(index + start); index + start < p.end
+    }
+
+  /** the subsequence from index `start' up to and excluding
+   *  the minimum of index `end' and the length of the current sequence.
+   */
+  override def slice(_start: Int, _end: Int) = {
+    page(start)
+    val s = start + _start
+    val e = if (_end == UndeterminedEnd) _end else start + _end
+    var f = first
+    while (f.end <= s && !f.isLast) f = f.next
+    new PagedSeq(more, f, s, e)
+  }
+
+  /** the subsequence from index `start' up to the
+   *  length of the current sequence.
+   */
+  override def slice(start: Int) = slice(start, UndeterminedEnd)
+
+  /** Convert sequence to string */
+  override def toString = {
+    val buf = new StringBuilder
+    for (ch <- elements) buf append ch
+    buf.toString
+  }
+}
+
+
+/** Page containing up to PageSize characters of the input sequence.
+ */
+private class Page[T](val num: Int) {
+
+  private final val PageSize = 4096
+
+  /** The next page in the sequence */
+  var next  : Page[T] = null
+
+  /** A later page in the sequence, serves a cachae for pointing to last page */
+  var later : Page[T] = this
+
+  /** The number of characters read into this page */
+  var filled: Int = 0
+
+  /** Is this page the permamnently last one in the sequence? Only true once `more'
+   *  method has returned -1 to signal end of input. */
+  var isLast: Boolean = false
+
+  /** The character array */
+  final val data = new Array[T](PageSize)
+
+  /** The index of the first character in this page relative to the whole sequence */
+  final def start = num * PageSize
+
+  /** The index of the character following the last charcater in this page relative
+   *  to the whole sequence */
+  final def end = start + filled
+
+  /** The currently last page in the sequence; might change as more charcaters are appended */
+  final def latest: Page[T] = {
+    if (later.next != null) later = later.next.latest
+    later
+  }
+
+  /** The character at given sequence index.
+   *  That index is relative to the whole sequence, not the page. */
+  def apply(index: Int) = {
+    if (index < start || index - start >= filled) throw new IndexOutOfBoundsException(index.toString)
+    data(index - start)
+  }
+
+  /** produces more characters by calling `more' and appends them on the current page,
+   *  or fills a subsequent page if current page is full
+   *  pre: if current page is full, it is the last one in the sequence.
+   */
+  final def addMore(more: (Array[T], Int, Int) => Int): Page[T] =
+    if (filled == PageSize) {
+      next = new Page[T](num + 1)
+      next.addMore(more)
+    } else {
+      val count = more(data, filled, PageSize - filled)
+      if (count < 0) isLast = true
+      else filled += count
+      this
+    }
+}
diff --git a/src/library/scala/runtime/RichString.scala b/src/library/scala/runtime/RichString.scala
index 192cf62ebb..412f2fd86c 100644
--- a/src/library/scala/runtime/RichString.scala
+++ b/src/library/scala/runtime/RichString.scala
@@ -14,7 +14,7 @@ package scala.runtime
 import Predef._
 import scala.util.matching.Regex
 
-final class RichString(val self: String) extends Proxy with CharSequence with RandomAccessSeq[Char] with Ordered[String] {
+final class RichString(val self: String) extends Proxy with RandomAccessSeq[Char] with Ordered[String] {
   import RichString._
   override def apply(n: Int) = self charAt n
   override def length = self.length
@@ -74,11 +74,6 @@ final class RichString(val self: String) extends Proxy with CharSequence with Ra
     new RichString(buf.toString)
   }
 
-  def charAt(index: Int) = self.charAt(index)
-
-  def subSequence(start: Int, end: Int): CharSequence =
-    new RichString(self.substring(start, end))
-
   /** return n times the current string
    */
   def * (n: Int): String = {
@@ -220,7 +215,7 @@ final class RichString(val self: String) extends Proxy with CharSequence with Ra
   def toFloat: Float     = java.lang.Float.parseFloat(self)
   def toDouble: Double   = java.lang.Double.parseDouble(self)
 
-  override def toArray: Array[Char] = {
+  def toArray: Array[Char] = {
     val result = new Array[Char](length)
     self.getChars(0, length, result, 0)
     result
diff --git a/src/library/scala/util/parsing/combinator/RegexParsers.scala b/src/library/scala/util/parsing/combinator/RegexParsers.scala
index 37b5f1d10c..49af37c8fc 100644
--- a/src/library/scala/util/parsing/combinator/RegexParsers.scala
+++ b/src/library/scala/util/parsing/combinator/RegexParsers.scala
@@ -13,6 +13,7 @@ package scala.util.parsing.combinator
 import java.util.regex.Pattern
 import scala.util.matching.Regex
 import scala.util.parsing.input._
+import scala.collection.immutable.PagedSeq
 
 trait RegexParsers extends Parsers {
 
@@ -22,9 +23,9 @@ trait RegexParsers extends Parsers {
 
   def skipWhitespace = whiteSpace.toString.length > 0
 
-  protected def handleWhiteSpace(source: CharSequence, offset: Int): Int =
+  protected def handleWhiteSpace(source: java.lang.CharSequence, offset: Int): Int =
     if (skipWhitespace)
-      (whiteSpace findPrefixMatchOf (source subSequence offset)) match {
+      (whiteSpace findPrefixMatchOf (source.subSequence(offset, source.length))) match {
         case Some(matched) => offset + matched.end
         case None => offset
       }
@@ -39,7 +40,7 @@ trait RegexParsers extends Parsers {
       val start = handleWhiteSpace(source, offset)
       var i = 0
       var j = start
-      while (i < s.length && source.isDefinedAt(j) && s.charAt(i) == source.charAt(j)) {
+      while (i < s.length && j < source.length && s.charAt(i) == source.charAt(j)) {
         i += 1
         j += 1
       }
@@ -56,7 +57,7 @@ trait RegexParsers extends Parsers {
       val source = in.source
       val offset = in.offset
       val start = handleWhiteSpace(source, offset)
-      (r findPrefixMatchOf (source subSequence start)) match {
+      (r findPrefixMatchOf (source.subSequence(start, source.length))) match {
         case Some(matched) =>
           Success(source.subSequence(start, start + matched.end).toString,
                   in.drop(start + matched.end - offset))
@@ -66,19 +67,27 @@ trait RegexParsers extends Parsers {
     }
   }
 
+  /** Parse some prefix of reader `in' with parser `p' */
+  def parse[T](p: Parser[T], in: Reader[Char]): ParseResult[T] =
+    p(in)
+
   /** Parse some prefix of character sequence `in' with parser `p' */
-  def parse[T](p: Parser[T], in: CharSequence): ParseResult[T] =
+  def parse[T](p: Parser[T], in: java.lang.CharSequence): ParseResult[T] =
     p(new CharSequenceReader(in))
 
   /** Parse some prefix of reader `in' with parser `p' */
-  def parse[T](p: Parser[T], in: Reader[Char]): ParseResult[T] =
-    p(in)
+  def parse[T](p: Parser[T], in: java.io.Reader): ParseResult[T] =
+    p(new PagedSeqReader(PagedSeq.fromReader(in)))
 
-  /** Parse all of character sequence `in' with parser `p' */
-  def parseAll[T](p: Parser[T], in: CharSequence): ParseResult[T] =
+  /** Parse all of reader `in' with parser `p' */
+  def parseAll[T](p: Parser[T], in: Reader[Char]): ParseResult[T] =
     parse(phrase(p), in)
 
   /** Parse all of reader `in' with parser `p' */
-  def parseAll[T](p: Parser[T], in: Reader[Char]): ParseResult[T] =
+  def parseAll[T](p: Parser[T], in: java.io.Reader): ParseResult[T] =
+    parse(phrase(p), in)
+
+  /** Parse all of character sequence `in' with parser `p' */
+  def parseAll[T](p: Parser[T], in: java.lang.CharSequence): ParseResult[T] =
     parse(phrase(p), in)
 }
diff --git a/src/library/scala/util/parsing/input/CharArrayReader.scala b/src/library/scala/util/parsing/input/CharArrayReader.scala
index 44e1b6eb6e..e8eef0e78c 100644
--- a/src/library/scala/util/parsing/input/CharArrayReader.scala
+++ b/src/library/scala/util/parsing/input/CharArrayReader.scala
@@ -32,7 +32,7 @@ object CharArrayReader {
  * @author Martin Odersky, Adriaan Moors
  */
 class CharArrayReader(chars: Array[Char], index: Int)
-extends CharSequenceReader(CharSequence.fromArray(chars), index) {
+extends CharSequenceReader(chars, index) {
 
   def this(chars: Array[Char]) = this(chars, 0)
 
diff --git a/src/library/scala/util/parsing/input/CharSequenceReader.scala b/src/library/scala/util/parsing/input/CharSequenceReader.scala
index bf1ad6e244..4b06808889 100644
--- a/src/library/scala/util/parsing/input/CharSequenceReader.scala
+++ b/src/library/scala/util/parsing/input/CharSequenceReader.scala
@@ -26,19 +26,19 @@ object CharSequenceReader {
  *
  * @author Martin Odersky
  */
-class CharSequenceReader(override val source: CharSequence,
+class CharSequenceReader(override val source: java.lang.CharSequence,
                          override val offset: Int) extends Reader[Char] {
   import CharSequenceReader._
 
   /** Construct a CharSequenceReader with its first element at
    *  source(0) and position (1,1).
    */
-  def this(source: CharSequence) = this(source, 0)
+  def this(source: java.lang.CharSequence) = this(source, 0)
 
   /** Returns the first element of the reader, or EofCh if reader is at its end
    */
   def first =
-    if (source.isDefinedAt(offset)) source(offset) else EofCh
+    if (offset < source.length) source.charAt(offset) else EofCh
 
   /** Returns a CharSequenceReader consisting of all elements except the first
    *
@@ -47,7 +47,7 @@ class CharSequenceReader(override val source: CharSequence,
    *         the rest of input.
    */
   def rest: CharSequenceReader =
-    if (source.isDefinedAt(offset)) new CharSequenceReader(source, offset + 1)
+    if (offset < source.length) new CharSequenceReader(source, offset + 1)
     else this
 
   /** The position of the first element in the reader
@@ -57,7 +57,7 @@ class CharSequenceReader(override val source: CharSequence,
   /** true iff there are no more elements in this reader (except for trailing
    *  EofCh's)
    */
-  def atEnd = !source.isDefinedAt(offset)
+  def atEnd = offset >= source.length
 
   /** Returns an abstract reader consisting of all elements except the first
    *  n elements.
diff --git a/src/library/scala/util/parsing/input/PagedSeqReader.scala b/src/library/scala/util/parsing/input/PagedSeqReader.scala
new file mode 100755
index 0000000000..f6139219ab
--- /dev/null
+++ b/src/library/scala/util/parsing/input/PagedSeqReader.scala
@@ -0,0 +1,71 @@
+/*                     __                                               *\
+**     ________ ___   / /  ___     Scala API                            **
+**    / __/ __// _ | / /  / _ |    (c) 2006-2007, LAMP/EPFL             **
+**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
+** /____/\___/_/ |_/____/_/ | |                                         **
+**                          |/                                          **
+\*                                                                      */
+
+// $Id: PagedSeqReader.scala 14416 2008-03-19 01:17:25Z mihaylov $
+
+package scala.util.parsing.input
+
+import scala.collection.immutable.PagedSeq
+
+/** An object encapsulating basic character constants
+ *
+ * @author Martin Odersky, Adriaan Moors
+ */
+object PagedSeqReader {
+  final val EofCh = '\032'
+}
+
+/** A character array reader reads a stream of characters (keeping track of their positions)
+ * from an array.
+ *
+ * @param source the source sequence
+ * @param offset  starting offset.
+ *
+ * @author Martin Odersky
+ */
+class PagedSeqReader(seq: PagedSeq[Char],
+                     override val offset: Int) extends Reader[Char] {
+  import PagedSeqReader._
+
+  override lazy val source: java.lang.CharSequence = seq
+
+  /** Construct a PagedSeqReader with its first element at
+   *  source(0) and position (1,1).
+   */
+  def this(seq: PagedSeq[Char]) = this(seq, 0)
+
+  /** Returns the first element of the reader, or EofCh if reader is at its end
+   */
+  def first =
+    if (seq.isDefinedAt(offset)) seq(offset) else EofCh
+
+  /** Returns a PagedSeqReader consisting of all elements except the first
+   *
+   * @return If atEnd is true, the result will be
+   *         this'; otherwise, it's a PagedSeqReader containing
+   *         the rest of input.
+   */
+  def rest: PagedSeqReader =
+    if (seq.isDefinedAt(offset)) new PagedSeqReader(seq, offset + 1)
+    else this
+
+  /** The position of the first element in the reader
+   */
+  def pos: Position = new OffsetPosition(source, offset)
+
+  /** true iff there are no more elements in this reader (except for trailing
+   *  EofCh's)
+   */
+  def atEnd = !seq.isDefinedAt(offset)
+
+  /** Returns an abstract reader consisting of all elements except the first
+   *  n elements.
+   */
+  override def drop(n: Int): PagedSeqReader =
+    new PagedSeqReader(seq, offset + n)
+}
diff --git a/src/library/scala/util/parsing/input/Reader.scala b/src/library/scala/util/parsing/input/Reader.scala
index 51cf7eeb47..d46173e416 100644
--- a/src/library/scala/util/parsing/input/Reader.scala
+++ b/src/library/scala/util/parsing/input/Reader.scala
@@ -18,15 +18,14 @@ package scala.util.parsing.input
  */
 abstract class Reader[+T] {
 
-  private[parsing] def source: CharSequence = this match {
-    case csr: CharSequenceReader => csr.source
-    case _ => throw new IllegalArgumentException("This kind of parser operates only on a CharSequenceReader")
-  }
+  /** If this is a reader over character sequences, the underlying char sequence
+   *  If not, throws a NoSuchMethodError exception.
+   */
+  def source: java.lang.CharSequence =
+    throw new NoSuchMethodError("not a char sequence reader")
 
-  private[parsing] def offset: Int = this match {
-    case csr: CharSequenceReader => csr.offset
-    case _ => throw new IllegalArgumentException("This kind of parser operates only on a CharSequenceReader")
-  }
+  def offset: Int =
+    throw new NoSuchMethodError("not a char sequence reader")
 
    /** Returns the first element of the reader
     */
diff --git a/src/library/scala/util/parsing/input/StreamReader.scala b/src/library/scala/util/parsing/input/StreamReader.scala
index f997590f18..a6fa1a7bcc 100644
--- a/src/library/scala/util/parsing/input/StreamReader.scala
+++ b/src/library/scala/util/parsing/input/StreamReader.scala
@@ -11,6 +11,7 @@
 package scala.util.parsing.input
 
 import java.io.BufferedReader
+import scala.collection.immutable.PagedSeq
 
 /** An object to create a StreamReader from a java.io.Reader.
  *
@@ -23,52 +24,52 @@ object StreamReader {
   final val EofCh = '\032'
 
   def apply(in: java.io.Reader): StreamReader = {
-    new StreamReader(new LazyCharSequence(in), 0, 1)
+    new StreamReader(PagedSeq.fromReader(in), 0, 1)
   }
 }
 
-/** A character array reader reads a stream of characters (keeping track of
- *  their positions) from an array.
+/** A StreamReader reads from a character sequence, typically created as a PagedSeq
+ *  from a java.io.Reader
  *
  *  NOTE:
  *  StreamReaders do not really fulfill the new contract for readers, which
  *  requires a `source' CharSequence representing the full input.
  *  Instead source is treated line by line.
- *  As a consequence, regex matching cannot extend beyond a single lines
+ *  As a consequence, regex matching cannot extend beyond a single line
  *  when a StreamReader are used for input.
  *
- * @param bin the underlying java.io.BufferedReader
- * @param sourceLine  the line at column `col' in the stream
- * @param line   the 1-based line number of the character returned by `first'
- * @param column the 1-based column number of the character returned by `first'
+ *  If you need to match regexes spanning several lines you should consider
+ *  class PagedSeqReader instead.
  *
- * @author Miles Sabin
+ *  @author Miles Sabin
+ *  @author Martin Odersky
  */
-sealed class StreamReader(source: CharSequence, offset: Int, lnum: Int) extends CharSequenceReader(source, offset) {
+sealed class StreamReader(seq: PagedSeq[Char], off: Int, lnum: Int) extends PagedSeqReader(seq, off) {
   import StreamReader._
 
-  override def rest: CharSequenceReader =
-    if (offset == source.length) this
-    else if (source(offset) == '\n') new StreamReader(source.subSequence(offset + 1), 0, lnum + 1)
-    else new StreamReader(source, offset + 1, lnum)
+  override def rest: StreamReader =
+    if (off == seq.length) this
+    else if (seq(off) == '\n')
+      new StreamReader(seq.slice(off + 1), 0, lnum + 1)
+    else new StreamReader(seq, off + 1, lnum)
 
   private def nextEol = {
-    var i = offset
-    while (i < source.length && source(i) != '\n' && source(i) != EofCh) i += 1
+    var i = off
+    while (i < seq.length && seq(i) != '\n' && seq(i) != EofCh) i += 1
     i
   }
 
   override def drop(n: Int): StreamReader = {
     val eolPos = nextEol
-    if (eolPos < offset + n && eolPos < source.length)
-      new StreamReader(source.subSequence(eolPos + 1), 0, lnum + 1).drop(offset + n - (eolPos + 1))
+    if (eolPos < off + n && eolPos < seq.length)
+      new StreamReader(seq.slice(eolPos + 1), 0, lnum + 1).drop(off + n - (eolPos + 1))
     else
-      new StreamReader(source, offset + n, lnum)
+      new StreamReader(seq, off + n, lnum)
   }
 
   override def pos: Position = new Position {
     def line = lnum
-    def column = offset + 1
-    def lineContents = source.subSequence(0, nextEol).toString
+    def column = off + 1
+    def lineContents = seq.slice(0, nextEol).toString
   }
 }
diff --git a/test/files/neg/bug414.check b/test/files/neg/bug414.check
index 3396a803f1..ec23e26337 100644
--- a/test/files/neg/bug414.check
+++ b/test/files/neg/bug414.check
@@ -1,4 +1,4 @@
-bug414.scala:5: error: pattern type is incompatibe with expected type;
+bug414.scala:5: error: pattern type is incompatible with expected type;
  found   : object Empty
  required: IntMap[a]
                 case Empty =>
diff --git a/test/files/run/caseclasses.scala b/test/files/run/caseclasses.scala
index b971cf3582..3afd7ee162 100644
--- a/test/files/run/caseclasses.scala
+++ b/test/files/run/caseclasses.scala
@@ -4,6 +4,9 @@ case class Bar
 
 case class Baz(override val x: Int, y: Int) extends Foo(x)(y)
 
+abstract class Base
+abstract case class Abs(x: Int) extends Base
+
 object M {
   abstract case class C(x: String) {}
   object C extends (String => C) {
@@ -16,6 +19,11 @@ object M {
 
 object Test extends Application {
 
+  def Abs(x: Int) = new Abs(x * 2){}
+  Abs(2) match {
+    case Abs(4) => ;
+  }
+
   def fn[a,b](x: a => b) = x;
   val f = fn(Foo(1))
   (f(2): AnyRef) match {
@@ -46,3 +54,4 @@ object Test extends Application {
   }
 
 }
+
-- 
cgit v1.2.3