diff options
-rw-r--r-- | doc/reference/ScalaReference.tex | 13 | ||||
-rw-r--r-- | sources/scala/List.scala | 20 | ||||
-rw-r--r-- | sources/scala/tools/scalac/ast/parser/Scanner.scala | 33 | ||||
-rw-r--r-- | sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala | 6 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Infer.scala | 28 | ||||
-rw-r--r-- | sources/scalac/ast/parser/Scanner.java | 28 | ||||
-rw-r--r-- | sources/scalac/typechecker/Infer.java | 19 |
7 files changed, 92 insertions, 55 deletions
diff --git a/doc/reference/ScalaReference.tex b/doc/reference/ScalaReference.tex index 3be6c66636..fa5a795b65 100644 --- a/doc/reference/ScalaReference.tex +++ b/doc/reference/ScalaReference.tex @@ -123,7 +123,7 @@ constructed from symbols in the following character sets: upper case letters ~\lstinline@`A' | $\ldots$ | `Z' | `$\Dollar$' | `_'@. \item Digits ~\lstinline@`0' | $\ldots$ | `9'@. \item Parentheses ~\lstinline@`(' | `)' | `[' | `]' | `{' | `}'@. -\item Delimiter characters ~\lstinline@`\' | `'' | `"' | `.' | `;' | `,'@. +\item Delimiter characters ~\lstinline@``' | `'' | `"' | `.' | `;' | `,'@. \item Operator characters. These include all printable ASCII characters which are in none of the sets above. \end{enumerate} @@ -139,7 +139,7 @@ varid ::= lower {letter $|$ digit} [`_' [id]] id ::= upper {letter $|$ digit} [`_' [id]] | varid | op - | `\' stringLit + | ``'string chars``' \end{lstlisting} There are three ways to form an identifier. First, an identifier can @@ -149,11 +149,10 @@ character followed by an arbitrary sequence of special characters. In the first case, the identifier prefix may be immediately followed by an underscore `\lstinline@_@' character and another string of characters that by themselves make up an identifier. Finally, an -identifier may also start with an escape character \lstinline@`\'@ -which is followed by an arbitrary string in apostrophes (host systems -may impose some restrictions on which strings are legal for -identifiers). As usual, a longest match rule applies. For instance, -the string +identifier may also be formed by an arbitrary string between +backquotes (host systems may impose some restrictions on which strings +are legal for identifiers). As usual, a longest match rule +applies. For instance, the string \begin{lstlisting} big_bob++=z3 diff --git a/sources/scala/List.scala b/sources/scala/List.scala index 135a998000..6ff50e2052 100644 --- a/sources/scala/List.scala +++ b/sources/scala/List.scala @@ -438,9 +438,7 @@ trait List[+a] extends Seq[a] { /** Combines the elements of this list together using the binary * operator <code>op</code>, from left to right, and starting with - * the value <code>z</code>. Similar to <code>fold</code> but with - * a different order of the arguments, allowing to use nice constructions like - * <code>(z foldLeft l) { ... }</code>. + * the value <code>z</code>. * @return <code>op(... (op(op(z,a0),a1) ...), an)</code> if the list * is <code>[a0, a1, ..., an]</code>. */ @@ -449,13 +447,27 @@ trait List[+a] extends Seq[a] { case x :: xs => xs.foldLeft[b](f(z, x))(f) }; + /** Combines the elements of this list together using the binary + * operator <code>op</code>, from rigth to left, and starting with + * the value <code>z</code>. + * @return <code>a0 op (... op (an op z)...)</code> if the list + * is <code>[a0, a1, ..., an]</code>. + */ def foldRight[b](z: b)(f: (a, b) => b): b = match { case Nil => z case x :: xs => f(x, xs.foldRight(z)(f)) }; + /** Similar to <code>foldLeft</code> but can be used as + * an operator with the order of list and zero arguments reversed. + * That is, <code>z /: xs</code> is the same as <code>xs foldLeft z</code> + */ def /:[b](z: b)(f: (b, a) => b): b = foldLeft(z)(f); - def :/[b](z: b)(f: (a, b) => b): b = foldRight(z)(f); + + /** An alias for <code>foldRight</code>. + * That is, <code>xs :\ z</code> is the same as <code>xs foldRight z</code> + */ + def :\[b](z: b)(f: (a, b) => b): b = foldRight(z)(f); def reduceLeft[b >: a](f: (b, b) => b): b = this match { case Nil => error("Nil.reduceLeft") diff --git a/sources/scala/tools/scalac/ast/parser/Scanner.scala b/sources/scala/tools/scalac/ast/parser/Scanner.scala index dac8c8eada..f890a0a6f6 100644 --- a/sources/scala/tools/scalac/ast/parser/Scanner.scala +++ b/sources/scala/tools/scalac/ast/parser/Scanner.scala @@ -199,19 +199,11 @@ class Scanner(_unit: Unit) extends TokenData { return; case '~' | '!' | '@' | '#' | '%' | '^' | '*' | '+' | '-' | '<' | - '>' | '?' | ':' | - '=' | '&' | '|' => + '>' | '?' | ':' | '=' | '&' | + '|' | '\\' => nextch(); getOperatorRest(index); return; - case '\\' => - nextch(); - if (ch == '"') { //" - getStringLit(); - token = IDENTIFIER; - } else - syntaxError(pos, "illegal character"); - return; case '/' => nextch(); if (!skipComment()) { @@ -231,8 +223,12 @@ class Scanner(_unit: Unit) extends TokenData { '5' | '6' | '7' | '8' | '9' => getNumber(index, 10); return; + case '`' => //" scala-mode: need to understand literals + getStringLit('`'); + token = IDENTIFIER; + return; case '\"' => //" scala-mode: need to understand literals - getStringLit(); + getStringLit('\"'); return; case '\'' => nextch(); @@ -407,8 +403,9 @@ class Scanner(_unit: Unit) extends TokenData { while (true) { ch match { case '~' | '!' | '@' | '#' | '%' | - '^' | '*' | '+' | '-' | '<' | - '>' | '?' | ':' | '=' | '&' | '|' => + '^' | '*' | '+' | '-' | '<' | + '>' | '?' | ':' | '=' | '&' | + '|' | '\\' => nextch(); case '/' => val lastbp = bp; @@ -443,20 +440,20 @@ class Scanner(_unit: Unit) extends TokenData { getIdentRest(index); case '~' | '!' | '@' | '#' | '%' | '^' | '*' | '+' | '-' | '<' | - '>' | '?' | ':' | - '=' | '&' | '|' | '/' => + '>' | '?' | ':' | '=' | '&' | + '|' | '\\' | '/' => getOperatorRest(index); case _ => treatIdent(index, bp); } } - private def getStringLit(): unit = { + private def getStringLit(delimiter: char): unit = { nextch(); litlen = 0; - while (ch != '\"'/*"*/ && ch != CR && ch != LF && ch != SU) + while (ch != delimiter && ch != CR && ch != LF && ch != SU) getlitch(); - if (ch == '\"'/*"*/) { + if (ch == delimiter) { token = STRINGLIT; name = Name.fromSource(lit, 0, litlen); nextch(); diff --git a/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala b/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala index 14d2fb3d0f..fe74bd5022 100644 --- a/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala +++ b/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala @@ -438,7 +438,7 @@ class TextTreePrinter(_out: PrintWriter, autoFlush: boolean) with TreePrinter { case Tree$Apply(fun, vargs) => if (fun.isInstanceOf[Tree$TypeTerm]) - print(fun.\"type"/*"*/.resultType().symbol().fullName().toString()); + print(fun.`type`.resultType().symbol().fullName().toString()); else print(fun); printArray(vargs, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP); @@ -485,7 +485,7 @@ class TextTreePrinter(_out: PrintWriter, autoFlush: boolean) with TreePrinter { printType(tree); case Tree$TypeTerm() => - print(tree.\"type"/*"*/.toString()); + print(tree.`type`.toString()); case Tree$SingletonType(ref) => print(ref); @@ -562,7 +562,7 @@ class TextTreePrinter(_out: PrintWriter, autoFlush: boolean) with TreePrinter { protected def printType(tree: Tree): unit = if (scalac_Global.instance.printtypes) { print(TXT_LEFT_BRACE); - print(if (tree.\"type"/*"*/ != null) Simple(tree.\"type"/*"*/.toString()) + print(if (tree.`type` != null) Simple(tree.`type`.toString()) else TXT_NULL); print(TXT_RIGHT_BRACE); } diff --git a/sources/scala/tools/scalac/typechecker/Infer.scala b/sources/scala/tools/scalac/typechecker/Infer.scala index 11214aec1e..8aee281d26 100644 --- a/sources/scala/tools/scalac/typechecker/Infer.scala +++ b/sources/scala/tools/scalac/typechecker/Infer.scala @@ -436,7 +436,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) { /** Automatically perform the following conversions on expression types: * A method type becomes the corresponding function type. - * A nullary method type becomes its result type. + * A nullary metAhod type becomes its result type. */ private def normalize(tp: Type): Type = tp match { case Type$MethodType(params, restype) => @@ -450,8 +450,28 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) { /** Is normalized type `tp' a subtype of prototype `pt'? */ - def isCompatible(tp: Type, pt: Type): boolean = - normalize(tp).isSubType(pt); + def isCompatible(tp: Type, pt: Type): boolean = { + val tp1 = normalize(tp); + if (tp1.isSubType(pt)) true + else { + val coerceMeth: Symbol = tp1.lookup(Names.coerce); + if (coerceMeth.kind == NONE) false + else tp1.memberType(coerceMeth) match { + case Type$PolyType(tparams, restype) if tparams.length == 0 => + restype.isSubType(pt) + case _ => + false + } + } + } + + def isCompatible(tps: Array[Type], pts: Array[Type]): boolean = { + { var i = 0; while (i < tps.length) { + if (!isCompatible(tps(i), pts(i))) return false; + i = i + 1 + }} + true + } /** Type arguments mapped to `scala.All' are taken to be uninstantiated. * Map all those type arguments to their corresponding type parameters @@ -768,7 +788,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) { val formals: Array[Type] = formalTypes(params, argtypes.length); isCompatible(restpe, pt) && formals.length == argtypes.length && - Type.isSubType(argtypes, formals); + isCompatible(argtypes, formals) case Type$PolyType(tparams, Type$MethodType(params, restpe)) => try { val targs: Array[Type] = methTypeArgs( diff --git a/sources/scalac/ast/parser/Scanner.java b/sources/scalac/ast/parser/Scanner.java index ae8a9ba187..8e0f57a2fb 100644 --- a/sources/scalac/ast/parser/Scanner.java +++ b/sources/scalac/ast/parser/Scanner.java @@ -221,21 +221,11 @@ public class Scanner extends TokenData { return; case '~': case '!': case '@': case '#': case '%': case '^': case '*': case '+': case '-': case '<': - case '>': case '?': case ':': + case '>': case '?': case ':': case '\\': case '=': case '&': case '|': nextch(); getOperatorRest(index); return; - case '\\': - nextch(); - if (ch == '"') { - getStringLit(); - token = IDENTIFIER; - } else { - syntaxError(pos, "illegal character"); - } - return; - case '/': nextch(); if (!skipComment()) { @@ -259,8 +249,12 @@ public class Scanner extends TokenData { case '5': case '6': case '7': case '8': case '9': getNumber(index, 10); return; + case '`': + getStringLit('`'); + token = IDENTIFIER; + return; case '\"': - getStringLit(); + getStringLit('\"'); return; case '\'': nextch(); @@ -438,7 +432,7 @@ public class Scanner extends TokenData { switch (ch) { case '~': case '!': case '@': case '#': case '%': case '^': case '*': case '+': case '-': case '<': - case '>': case '?': case ':': + case '>': case '?': case ':': case '\\': case '=': case '&': case '|': nextch(); break; @@ -482,7 +476,7 @@ public class Scanner extends TokenData { return; case '~': case '!': case '@': case '#': case '%': case '^': case '*': case '+': case '-': case '<': - case '>': case '?': case ':': + case '>': case '?': case ':': case '\\': case '=': case '&': case '|': case '/': getOperatorRest(index); @@ -497,12 +491,12 @@ public class Scanner extends TokenData { } } - private void getStringLit() { + private void getStringLit(char delimiter) { nextch(); litlen = 0; - while (ch != '\"' && ch != CR && ch != LF && ch != SU) + while (ch != delimiter && ch != CR && ch != LF && ch != SU) getlitch(); - if (ch == '\"') { + if (ch == delimiter) { token = STRINGLIT; name = Name.fromSource(lit, 0, litlen); nextch(); diff --git a/sources/scalac/typechecker/Infer.java b/sources/scalac/typechecker/Infer.java index b2b38ef2da..715b6d0f07 100644 --- a/sources/scalac/typechecker/Infer.java +++ b/sources/scalac/typechecker/Infer.java @@ -579,7 +579,22 @@ public class Infer implements Modifiers, Kinds { /** Is normalized type `tp' a subtype of prototype `pt'? */ public boolean isCompatible(Type tp, Type pt) { - return normalize(tp).isSubType(pt); + Type tp1 = normalize(tp); + if (tp1.isSubType(pt)) return true; + Symbol coerceMeth = tp1.lookup(Names.coerce); + if (coerceMeth.kind == NONE) return false; + switch (tp1.memberType(coerceMeth)) { + case PolyType(Symbol[] tparams, Type restype): + if (tparams.length == 0) + return restype.isSubType(pt); + } + return false; + } + + public boolean isCompatible(Type[] tps, Type[] pts) { + for (int i = 0; i < tps.length; i++) + if (!isCompatible(tps[i], pts[i])) return false; + return true; } /** Type arguments mapped to `scala.All' are taken to be uninstantiated. @@ -886,7 +901,7 @@ public class Infer implements Modifiers, Kinds { return isCompatible(restpe, pt) && formals.length == argtypes.length && - Type.isSubType(argtypes, formals); + isCompatible(argtypes, formals); case PolyType(Symbol[] tparams, MethodType(Symbol[] params, Type restpe)): try { Type[] targs = methTypeArgs( |