summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/list/scalac.lst1
-rw-r--r--doc/reference/ExamplesPart.tex14
-rw-r--r--sources/scala/Console.scala1
-rw-r--r--sources/scala/Enumeration.scala5
-rw-r--r--sources/scala/List.scala6
-rw-r--r--sources/scala/Ord.scala5
-rw-r--r--sources/scala/tools/scalac/ast/parser/Parser.scala37
-rw-r--r--sources/scala/tools/scalac/ast/parser/Scanner.scala117
-rw-r--r--sources/scala/tools/scalac/ast/parser/TokenData.scala8
-rw-r--r--sources/scala/tools/scalac/typechecker/Analyzer.scala56
-rw-r--r--sources/scala/tools/scalac/typechecker/Context.scala42
-rw-r--r--sources/scala/tools/scalac/typechecker/ImportList.scala21
-rw-r--r--sources/scala/tools/scalac/typechecker/Infer.scala58
-rw-r--r--sources/scalac/ast/TreeInfo.java25
-rw-r--r--sources/scalac/util/Names.java1
15 files changed, 275 insertions, 122 deletions
diff --git a/config/list/scalac.lst b/config/list/scalac.lst
index fdc3823814..131741ca79 100644
--- a/config/list/scalac.lst
+++ b/config/list/scalac.lst
@@ -31,6 +31,7 @@ typechecker/DeSugarize.scala
typechecker/ImportList.scala
typechecker/Infer.scala
typechecker/Substituter.scala
+typechecker/Coerce.scala
util/NewArray.scala
diff --git a/doc/reference/ExamplesPart.tex b/doc/reference/ExamplesPart.tex
index 30ea725cfd..483a56f74b 100644
--- a/doc/reference/ExamplesPart.tex
+++ b/doc/reference/ExamplesPart.tex
@@ -75,10 +75,10 @@ functional style.
def sort(xs: List[int]): List[int] =
if (xs.length <= 1) xs
else {
- val pivot = a(a.length / 2);
- sort(a.filter(x => x < pivot))
- ::: a.filter(x => x == pivot)
- ::: sort(a.filter(x => x > pivot))
+ val pivot = xs(xs.length / 2);
+ sort(xs.filter(x => x < pivot))
+ ::: xs.filter(x => x == pivot)
+ ::: sort(xs.filter(x => x > pivot))
}
\end{lstlisting}
@@ -1605,7 +1605,7 @@ a more streamlined alternative definition of the empty set:
\begin{lstlisting}
object EmptySet extends IntSet {
def contains(x: int): boolean = false;
- def incl(x: int): IntSet = new NonEmptySet(x, empty, empty);
+ def incl(x: int): IntSet = new NonEmptySet(x, EmptySet, EmptySet);
}
\end{lstlisting}
The syntax of an object definition follows the syntax of a class
@@ -2761,7 +2761,7 @@ A list containing the elements \code{x}$_1$, \ldots, \code{x}$_n$ is written
\begin{lstlisting}
val fruit = List("apples", "oranges", "pears");
val nums = List(1, 2, 3, 4);
-val diag3 = List(List(1, 0, 0), List(0, 1, 0));
+val diag3 = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1));
val empty = List();
\end{lstlisting}
Lists are similar to arrays in languages such as C or Java, but there
@@ -2779,7 +2779,7 @@ list all have the same type. The type of a list with elements of type
\begin{lstlisting}
val fruit: List[String] = List("apples", "oranges", "pears");
val nums : List[int] = List(1, 2, 3, 4);
-val diag3: List[List[int]] = List(List(1, 0, 0), List(0, 1, 0));
+val diag3: List[List[int]] = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1));
val empty: List[int] = List();
\end{lstlisting}
diff --git a/sources/scala/Console.scala b/sources/scala/Console.scala
index f3017e6b11..ec01840e0f 100644
--- a/sources/scala/Console.scala
+++ b/sources/scala/Console.scala
@@ -120,6 +120,7 @@ object Console {
* @param args the parameters used to instantiate the format.
*/
def printf(text: String)(args: Any*): Unit = {
+ // todo: Uncurry
if (text == null)
out.print("null");
else
diff --git a/sources/scala/Enumeration.scala b/sources/scala/Enumeration.scala
index 44e478d0ab..c084c717e7 100644
--- a/sources/scala/Enumeration.scala
+++ b/sources/scala/Enumeration.scala
@@ -86,7 +86,10 @@ abstract class Enumeration(initial: Int, names: String*) {
trait Value extends Ord[Value] {
def id: Int;
- def < (that: Value): Boolean = id < that.id;
+ def < [S >: Value <: Ord[S]](that: S): Boolean = that match {
+ case that1: Value => id < that1.id
+ case _ => that > this
+ }
}
protected class Val(i: Int, name: String) extends Value {
diff --git a/sources/scala/List.scala b/sources/scala/List.scala
index 609f71e9d3..fc5c8a63c5 100644
--- a/sources/scala/List.scala
+++ b/sources/scala/List.scala
@@ -441,7 +441,11 @@ trait List[+a] extends Seq[a] {
def filter(p: a => Boolean): List[a] = match {
case Nil => this
case head :: tail =>
- if (p(head)) head :: (tail filter p) else tail filter p
+ val tail1 = tail filter p;
+ if (p(head))
+ if (tail eq tail1) this
+ else head :: tail1
+ else tail1
};
/** Remove all elements of the list which satisfy the predicate
diff --git a/sources/scala/Ord.scala b/sources/scala/Ord.scala
index aa55504c39..ff352ac584 100644
--- a/sources/scala/Ord.scala
+++ b/sources/scala/Ord.scala
@@ -9,6 +9,8 @@
package scala;
+/* Shall we use a nonvariant Ord?
+
trait Ord[t <: Ord[t]]: t {
def < (that: t): Boolean;
def <=(that: t): Boolean = this < that || this == that;
@@ -16,7 +18,7 @@ trait Ord[t <: Ord[t]]: t {
def >=(that: t): Boolean = that <= this;
}
-/* Shall we use a covariant Ord?
+*/
trait Ord[+T <: Ord[T]] {
def < [S >: T <: Ord[S]](that: S): Boolean;
@@ -24,4 +26,3 @@ trait Ord[+T <: Ord[T]] {
def > [S >: T <: Ord[S]](that: S): Boolean = that < this;
def >=[S >: T <: Ord[S]](that: S): Boolean = that <= this;
}
-*/
diff --git a/sources/scala/tools/scalac/ast/parser/Parser.scala b/sources/scala/tools/scalac/ast/parser/Parser.scala
index abd8e9d822..f3c8cfbc0d 100644
--- a/sources/scala/tools/scalac/ast/parser/Parser.scala
+++ b/sources/scala/tools/scalac/ast/parser/Parser.scala
@@ -572,18 +572,18 @@ class Parser(unit: Unit) {
* | symbol [ArgumentExprs]
* | null
*/
- def literal(isPattern: boolean): Tree = {
+ def literal(isPattern: boolean, isNegated: boolean): Tree = {
def litToTree() = s.token match {
case CHARLIT =>
gen.mkCharLit(s.pos, s.intVal.asInstanceOf[char])
case INTLIT =>
- gen.mkIntLit(s.pos, s.intVal.asInstanceOf[int])
+ gen.mkIntLit(s.pos, s.intVal(isNegated).asInstanceOf[int])
case LONGLIT =>
- gen.mkLongLit(s.pos, s.intVal)
+ gen.mkLongLit(s.pos, s.intVal(isNegated))
case FLOATLIT =>
- gen.mkFloatLit(s.pos, s.floatVal.asInstanceOf[float])
+ gen.mkFloatLit(s.pos, s.floatVal(isNegated).asInstanceOf[float])
case DOUBLELIT =>
- gen.mkDoubleLit(s.pos, s.floatVal)
+ gen.mkDoubleLit(s.pos, s.floatVal(isNegated))
case STRINGLIT | SYMBOLLIT =>
gen.mkStringLit(s.pos, s.name.toString())
case TRUE =>
@@ -921,9 +921,16 @@ class Parser(unit: Unit) {
/** PrefixExpr ::= [`-' | `+' | `~' | `!'] SimpleExpr
*/
def prefixExpr(): Tree =
- if (s.token == IDENTIFIER &&
- (s.name == MINUS ||
- s.name == PLUS ||
+ if (s.token == IDENTIFIER && s.name == MINUS) {
+ val name = ident();
+ s.token match {
+ case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT =>
+ return literal(false, true);
+ case _ =>
+ make.Select(s.pos, simpleExpr(), name);
+ }
+ } else if (s.token == IDENTIFIER &&
+ (s.name == PLUS ||
s.name == TILDE ||
s.name == BANG)) {
val name = ident();
@@ -947,7 +954,7 @@ class Parser(unit: Unit) {
s.token match {
case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT |
SYMBOLLIT | TRUE | FALSE | NULL =>
- t = literal(false);
+ t = literal(false, false);
case IDENTIFIER | THIS | SUPER =>
t = if( s.xStartsXML ) {
xmlp.xLiteral;
@@ -1263,6 +1270,14 @@ class Parser(unit: Unit) {
xmlp.xLiteralPattern
} else {
var t = stableId();
+ s.token match {
+ case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT =>
+ t match {
+ case Tree$Ident(name) if name == Names.MINUS =>
+ return literal(true, true);
+ }
+ case _ =>
+ }
while (s.token == LPAREN) {
var ts = Tree.EMPTY_ARRAY;
accept(LPAREN);
@@ -1276,7 +1291,7 @@ class Parser(unit: Unit) {
case USCORE =>
make.Ident(s.skipToken(), Names.PATTERN_WILDCARD)
case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL =>
- literal(true)
+ literal(true, false)
case LPAREN =>
val p = s.pos;
s.nextToken();
@@ -1923,6 +1938,8 @@ class Parser(unit: Unit) {
isModifier()) {
stats.append(joinComment(clsDef(modifiers())));
} else if (s.token != SEMI) {
+ System.out.println(s.token);
+ System.out.println(s.name);
syntaxError("illegal start of class or object definition", true);
}
if (s.token != RBRACE && s.token != EOF) accept(SEMI);
diff --git a/sources/scala/tools/scalac/ast/parser/Scanner.scala b/sources/scala/tools/scalac/ast/parser/Scanner.scala
index 7814b2d25a..ab6d307c0c 100644
--- a/sources/scala/tools/scalac/ast/parser/Scanner.scala
+++ b/sources/scala/tools/scalac/ast/parser/Scanner.scala
@@ -63,7 +63,7 @@ class Scanner(_unit: Unit) extends TokenData {
/** the input buffer:
*/
var buf: Array[byte] = unit.source.bytes();
- var bp: int = -1;
+ private var bp: int = -1;
/** the current character
*/
@@ -89,6 +89,7 @@ class Scanner(_unit: Unit) extends TokenData {
def nextch(): unit = {
bp = bp + 1; ch = buf(bp); ccol = ccol + 1;
+ //System.out.print(bp + "[" + (ch.asInstanceOf[char]) + "]");//DEBUG
}
/** read next token and return last position
@@ -141,7 +142,7 @@ class Scanner(_unit: Unit) extends TokenData {
this.copyFrom(prev);
}
}
- //System.out.println("<" + token2string(token) + ">");//DEBUG
+ //System.out.println("<" + token2string(token) + ":" + name + ">");//DEBUG
}
}
@@ -206,14 +207,17 @@ class Scanner(_unit: Unit) extends TokenData {
nextch();
if (ch == 'x' || ch == 'X') {
nextch();
- getNumber(index + 2, 16);
+ base = 16;
+ getNumber(index + 2);
} else {
- getNumber(index, 8);
+ base = 8;
+ getNumber(index);
}
return; // scala-mode: return is a keyword
case '1' | '2' | '3' | '4' |
'5' | '6' | '7' | '8' | '9' =>
- getNumber(index, 10);
+ base = 10;
+ getNumber(index);
return;
case '`' => //" scala-mode: need to understand literals
getStringLit('`');
@@ -252,12 +256,6 @@ class Scanner(_unit: Unit) extends TokenData {
if (ch == '\'') {
nextch();
token = CHARLIT;
- val ascii = new Array[byte](litlen * 2);
- val alen = SourceRepresentation.source2ascii(lit, 0, litlen, ascii);
- if (alen > 0)
- intVal = SourceRepresentation.ascii2string(ascii, 0, alen).charAt(0);
- else
- intVal = 0;
} else {
syntaxError("unclosed character literal");
}
@@ -534,7 +532,6 @@ class Scanner(_unit: Unit) extends TokenData {
}
/** read fractional part of floating point number;
- * Then floatVal := buf[index..], converted to a floating point number.
*/
protected def getFraction(index: int) = {
while (SourceRepresentation.digit2int(ch, 10) >= 0) {
@@ -556,54 +553,76 @@ class Scanner(_unit: Unit) extends TokenData {
nextch();
}
}
- var limit = Double.MAX_VALUE;
if ((ch == 'd') || (ch == 'D')) {
nextch();
} else if ((ch == 'f') || (ch == 'F')) {
token = FLOATLIT;
- limit = Float.MAX_VALUE;
nextch();
}
+ name = Name.fromAscii(buf, index, bp - index);
+ }
+
+ /** convert name, base to long value
+ * base = the base of the number; one of 8, 10, 16.
+ */
+ def intVal(negated: boolean): long = {
+ if (token == CHARLIT && !negated) {
+ val ascii = new Array[byte](litlen * 2);
+ val alen = SourceRepresentation.source2ascii(lit, 0, litlen, ascii);
+ if (alen > 0)
+ SourceRepresentation.ascii2string(ascii, 0, alen).charAt(0)
+ else
+ 0
+ } else {
+ var value: long = 0;
+ val divider = if (base == 10) 1 else 2;
+ val limit: long = if (token == LONGLIT) Long.MAX_VALUE else Integer.MAX_VALUE;
+ var i = 0;
+ val len = name.length();
+ while (i < len) {
+ val d = SourceRepresentation.digit2int(name sub i, base);
+ if (d < 0) {
+ syntaxError("malformed integer number");
+ return 0;
+ }
+ if (value < 0 ||
+ limit / (base / divider) < value ||
+ limit - (d / divider) < value * (base / divider) &&
+ !(negated && limit == value * base - 1 + d)) {
+ syntaxError("integer number too large");
+ return 0;
+ }
+ value = value * base + d;
+ i = i + 1;
+ }
+ if (negated) -value else value
+ }
+ }
+
+ def intVal: long = intVal(false);
+
+ /** convert name, base to double value
+ */
+ def floatVal(negated: boolean): double = {
+ val limit: double =
+ if (token == DOUBLELIT) Double.MAX_VALUE else Float.MAX_VALUE;
try {
- floatVal = Double.valueOf(new String(buf, index, bp - index)).doubleValue();
- if (floatVal > limit)
+ val value = Double.valueOf(name.toString()).doubleValue();
+ if (value > limit)
syntaxError("floating point number too large");
+ if (negated) -value else value
} catch {
case _: NumberFormatException =>
syntaxError("malformed floating point number");
+ 0.0
}
}
- /** intVal := buf(index..index+len-1), converted to an integer number.
- * base = the base of the number; one of 8, 10, 16.
- * max = the maximal number before an overflow.
- */
- protected def makeInt (index: int, len: int, base: int, max: long): unit = {
- intVal = 0;
- val divider = if (base == 10) 1 else 2;
- var i = 0;
- while (i < len) {
- val d = SourceRepresentation.digit2int(buf(index + i), base);
- if (d < 0) {
- syntaxError("malformed integer number");
- return;
- }
- if (intVal < 0 ||
- max / (base / divider) < intVal ||
- max - (d / divider) < (intVal * (base / divider) - 0)) {
- syntaxError("integer number too large");
- return;
- }
- intVal = intVal * base + d;
- i = i + 1;
- }
- }
+ def floatVal: double = floatVal(false);
- /** read a number,
- * and convert buf[index..], setting either intVal or floatVal.
- * base = the base of the number; one of 8, 10, 16.
+ /** read a number into name and set base
*/
- protected def getNumber(index: int, base: int) = {
+ protected def getNumber(index: int) = {
while (SourceRepresentation.digit2int(ch, if (base == 8) 10 else base) >= 0) {
nextch();
}
@@ -630,9 +649,8 @@ class Scanner(_unit: Unit) extends TokenData {
ch == '$' || ch == '_') {
bp = bp - 1;
ch = buf(bp);
- ccol = ccol - 1;
- makeInt(index, bp - index, base, Integer.MAX_VALUE);
- intVal = intVal.asInstanceOf[int];
+ ccol = ccol - 1;
+ name = Name.fromAscii(buf, index, bp - index);
token = INTLIT;
} else
getFraction(index);
@@ -643,12 +661,11 @@ class Scanner(_unit: Unit) extends TokenData {
getFraction(index);
} else {
if (ch == 'l' || ch == 'L') {
- makeInt(index, bp - index, base, Long.MAX_VALUE);
+ name = Name.fromAscii(buf, index, bp - index);
nextch();
token = LONGLIT;
} else {
- makeInt(index, bp - index, base, Integer.MAX_VALUE);
- intVal = intVal.asInstanceOf[int];
+ name = Name.fromAscii(buf, index, bp - index);
token = INTLIT;
}
}
diff --git a/sources/scala/tools/scalac/ast/parser/TokenData.scala b/sources/scala/tools/scalac/ast/parser/TokenData.scala
index ab3b0ba9f5..43f11e18de 100644
--- a/sources/scala/tools/scalac/ast/parser/TokenData.scala
+++ b/sources/scala/tools/scalac/ast/parser/TokenData.scala
@@ -31,17 +31,15 @@ class TokenData {
*/
var name: Name = null;
- /** the value of a number
+ /** the base of a number
*/
- var intVal: long = 0;
- var floatVal: double = 0;
+ var base: int = 0;
def copyFrom(td: TokenData) = {
this.token = td.token;
this.pos = td.pos;
this.name = td.name;
- this.intVal = td.intVal;
- this.floatVal = td.floatVal;
+ this.base = td.base;
}
}
}
diff --git a/sources/scala/tools/scalac/typechecker/Analyzer.scala b/sources/scala/tools/scalac/typechecker/Analyzer.scala
index afaab26e79..9a8862d567 100644
--- a/sources/scala/tools/scalac/typechecker/Analyzer.scala
+++ b/sources/scala/tools/scalac/typechecker/Analyzer.scala
@@ -39,13 +39,6 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
import Modifiers._;
import Kinds._;
- val definitions = global.definitions;
- val infer = new scala.tools.scalac.typechecker.Infer(this);
- val desugarize = new DeSugarize(make, copy, gen, infer, global);
- val constfold = new ConstantFolder(global);
-
- var unit: Unit = _;
-
private var context: Context = _;
private var pt: Type = _;
private var mode: int = _;
@@ -53,6 +46,15 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
private var inAlternative: boolean = _;
private var patternVars: HashMap = _; // for pattern matching; maps x to {true,false}
+ val definitions = global.definitions;
+ val infer = new scala.tools.scalac.typechecker.Infer(this) {
+ override def getCoerceMeths = { context.coerceMeths; }
+ }
+ val desugarize = new DeSugarize(make, copy, gen, infer, global);
+ val constfold = new ConstantFolder(global);
+
+ var unit: Unit = _;
+
override def apply(units: Array[Unit]): unit = {
var i = 0; while (i < units.length) {
enterUnit(units(i));
@@ -87,6 +89,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
def enter(context: Context, unit: Unit): unit = {
assert(this.unit == null, "start unit non null for " + unit);
+ context.infer = infer;
this.unit = unit;
this.context = context;
this.patternVars = new HashMap();
@@ -1221,14 +1224,13 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
checkStable(expr);
owntype = expr.getType();
val tp: Type = owntype.widen();
- var i = 0; while (i < selectors.length) {
+ { var i = 0; while (i < selectors.length) {
if (selectors(i) != Names.IMPORT_WILDCARD &&
tp.lookup(selectors(i)) == Symbol.NONE &&
tp.lookup(selectors(i).toTypeName()) == Symbol.NONE)
error(tree.pos, "" + NameTransformer.decode(selectors(i)) + " is not a member of " + expr);
i = i + 2
- }
-
+ }}
case _ =>
throw new ApplicationError();
}
@@ -1526,14 +1528,30 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
if (pt.symbol() == definitions.UNIT_CLASS) {
return gen.mkUnitBlock(tree);
} else if (infer.isCompatible(tree.getType(), pt)) {
- val coerceMeth: Symbol = tree.getType().lookup(Names.coerce);
- if (coerceMeth != Symbol.NONE) {
- val coerceType: Type = checkAccessible(
- tree.pos, coerceMeth, tree.getType().memberType(coerceMeth),
- tree, tree.getType());
- val tree1 = make.Select(tree.pos, tree, Names.coerce)
- .setSymbol(coerceMeth)
- .setType(coerceType);
+ val coerce = infer.bestCoerce(tree.getType(), pt);
+ if (coerce != null) {
+ val coerceFn =
+ if (coerce.qual == Tree.Empty) {
+ make.Ident(tree.pos, Names.view)
+ .setSymbol(coerce.sym).setType(coerce.symtype)
+ } else {
+ val coercetype = checkAccessible(
+ tree.pos, coerce.sym, coerce.symtype, coerce.qual, coerce.qual.getType());
+ make.Select(tree.pos, coerce.qual, Names.view)
+ .setSymbol(coerce.sym).setType(coercetype)
+ }
+ val tree1 = gen.Apply(coerceFn, NewArray.Tree(tree));
+ return adapt(tree1, mode, pt);
+ }
+ // todo: remove
+ val coerceMeth: Symbol = tree.getType().lookup(Names.coerce);
+ if (coerceMeth != Symbol.NONE) {
+ val coerceType: Type = checkAccessible(
+ tree.pos, coerceMeth, tree.getType().memberType(coerceMeth),
+ tree, tree.getType());
+ val tree1 = make.Select(tree.pos, tree, Names.coerce)
+ .setSymbol(coerceMeth)
+ .setType(coerceType);
return adapt(tree1, mode, pt);
}
}
@@ -1798,7 +1816,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
/** Attribute a template
*/
def transformTemplate(templ: Tree$Template, owner: Symbol): Tree$Template = {
- if (global.debug) global.log("transforming template of " + owner);//debug
+ //if (global.debug) global.log("transforming template of " + owner);//DEBUG
if (templ.getType() == null)
defineTemplate(templ, owner, owner.members());//may happen for mixins
//System.out.println(owner.info());//DEBUG
diff --git a/sources/scala/tools/scalac/typechecker/Context.scala b/sources/scala/tools/scalac/typechecker/Context.scala
index 56e3852a18..a245aeb437 100644
--- a/sources/scala/tools/scalac/typechecker/Context.scala
+++ b/sources/scala/tools/scalac/typechecker/Context.scala
@@ -7,24 +7,30 @@
\* */
import scalac.symtab._;
import scalac.ast._;
+import scalac.util.Names;
package scala.tools.scalac.typechecker {
object Context {
val NONE = new Context();
+ NONE.coerceCache = List();
}
class Context {
+ import Kinds._;
+
var tree: Tree = _; // Tree associated with this context
var owner: Symbol = _; // The current owner
var scope: Scope = _; // The current scope
- var imports: ImportList = _; // The current import list
+ var imports: ImportList = null; // The current import list
var outer: Context = _; // The next outer context
var enclClass: Context = this; // The next outer context whose tree
// is a class template
var variance: int = _; // Variance relative to enclosing class.
var constructorClass: Symbol = _; // Class for auxiliary constructor
+ var coerceCache: List[Coerce] = null; // Coerce symbols visible in scope
+ var infer: Infer = null; // Type inferencer
def this(tree: Tree, owner: Symbol, scope: Scope, outer: Context) = {
this();
@@ -38,6 +44,7 @@ class Context {
else outer.enclClass;
this.variance = outer.variance;
this.constructorClass = outer.constructorClass;
+ this.infer = outer.infer;
this.outer = outer;
}
@@ -60,5 +67,38 @@ class Context {
case _ =>
outer.isTopLevel()
}
+
+ def coerceMeths: List[Coerce] = {
+
+ def addCoerce(sym: Symbol, symtype: Type, qual: Tree): unit = symtype match {
+ case Type$OverloadedType(alts, alttypes) =>
+ var i = 0;
+ while (i < alts.length) {
+ addCoerce(alts(i), alttypes(i), qual);
+ i = i + 1;
+ }
+ case _ =>
+ def isUnShadowed(coerce: Coerce) =
+ coerce.context == this || !infer.specializes(coerce.symtype, symtype);
+ val coerce = new Coerce(sym, symtype, qual, this);
+ System.out.println("COERCE " + symtype + " " + qual);
+ coerceCache = coerce :: coerceCache.filter(isUnShadowed);
+ }
+
+ if (coerceCache == null) {
+ coerceCache = outer.coerceMeths;
+ val e = scope.lookupEntry(Names.view);
+ if (e.owner == scope && e.sym.kind == VAL)
+ addCoerce(e.sym, e.sym.getType(), Tree.Empty);
+ var imp = imports;
+ while (imp != outer.imports) {
+ val sym = imp.importedSymbol(Names.view);
+ if (sym.kind == VAL)
+ addCoerce(sym, imp.importType().memberType(sym), imp.importPrefix());
+ imp = imp.prev;
+ }
+ }
+ coerceCache
+ }
}
}
diff --git a/sources/scala/tools/scalac/typechecker/ImportList.scala b/sources/scala/tools/scalac/typechecker/ImportList.scala
index 136aa5474f..0ff717965a 100644
--- a/sources/scala/tools/scalac/typechecker/ImportList.scala
+++ b/sources/scala/tools/scalac/typechecker/ImportList.scala
@@ -41,26 +41,7 @@ case class ImportList(tree: Tree, enclScope: Scope, prev: ImportList) {
this.importType().isSameAs(that.importType());
def importedSymbol(name: Name): Symbol = {
- val t = this.importType();
- var renamed = false;
- tree match {
- case Tree$Import(expr, selectors) =>
- var i = 0;
- while (i < selectors.length) {
- if (i + 1 < selectors.length && name.toTermName() == selectors(i+1)) {
- if (name.isTypeName())
- return t.lookupNonPrivate(selectors(i).toTypeName());
- else
- return t.lookupNonPrivate(selectors(i));
- } else if (name.toTermName() == selectors(i)) {
- renamed = true;
- } else if (selectors(i) == Names.IMPORT_WILDCARD && !renamed) {
- return t.lookupNonPrivate(name);
- }
- i = i + 2
- }
- Symbol.NONE
- }
+ return TreeInfo.importedSymbol(tree, name);
}
}
}
diff --git a/sources/scala/tools/scalac/typechecker/Infer.scala b/sources/scala/tools/scalac/typechecker/Infer.scala
index 5edc10d53e..74ed2d8cad 100644
--- a/sources/scala/tools/scalac/typechecker/Infer.scala
+++ b/sources/scala/tools/scalac/typechecker/Infer.scala
@@ -28,6 +28,10 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
def this(trans: Transformer) = this(trans.global, trans.gen, trans.make);
+// Coerce generator, overridable */
+
+ def getCoerceMeths: List[Coerce] = List();
+
// Error messages -------------------------------------------------------------
def applyErrorMsg(msg1: String, fn: Tree, msg2: String, argtypes: Array[Type], pt: Type): String =
@@ -465,8 +469,16 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
val tp1 = normalize(tp);
if (tp1.isSubType(pt)) true
else {
- val coerceMeth: Symbol = tp1.lookup(Names.coerce);
- coerceMeth.kind != NONE && canCoerce(tp1.memberType(coerceMeth));
+ val argtypes = NewArray.Type(tp1);
+ var coerceMeths = getCoerceMeths;
+ while (!coerceMeths.isEmpty && !isApplicable(coerceMeths.head.symtype, argtypes, pt, false))
+ coerceMeths = coerceMeths.tail;
+ if (!coerceMeths.isEmpty) true
+ // todo: remove
+ else {
+ val coerceMeth: Symbol = tp1.lookup(Names.coerce);
+ coerceMeth.kind != NONE && canCoerce(tp1.memberType(coerceMeth));
+ }
}
}
@@ -787,13 +799,17 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
/** Is function type `ftpe' applicable to `argtypes' and
* does its result conform to `pt'?
*/
- def isApplicable(ftpe: Type, argtypes: Array[Type], pt: Type): boolean = ftpe match {
+ def isApplicable(ftpe: Type, argtypes: Array[Type], pt: Type): boolean =
+ isApplicable(ftpe, argtypes, pt, true);
+
+ def isApplicable(ftpe: Type, argtypes: Array[Type], pt: Type,
+ coercible: boolean): boolean = ftpe match {
case Type$MethodType(params, restpe) =>
// sequences ? List( a* )
val formals: Array[Type] = formalTypes(params, argtypes.length);
- isCompatible(restpe, pt) &&
formals.length == argtypes.length &&
- isCompatible(argtypes, formals)
+ (if (coercible) isCompatible(argtypes, formals) && isCompatible(restpe, pt)
+ else Type.isSubType(argtypes, formals) && restpe.isSubType(pt));
case Type$PolyType(tparams, Type$MethodType(params, restpe)) =>
try {
val targs: Array[Type] = methTypeArgs(
@@ -944,6 +960,36 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
tree.setSymbol(alts(i)).setType(alttypes(i));
}
}
-}
+ /** return coerce which best matches argument type `tp' and expected type `pt'.
+ */
+ def bestCoerce(tp: Type, pt: Type): Coerce = {
+ var best: Coerce = null;
+ var coerceMeths = getCoerceMeths;
+ val argtypes = NewArray.Type(tp);
+ while (!coerceMeths.isEmpty) {
+ if (isApplicable(coerceMeths.head.symtype, argtypes, pt, false) &&
+ (best == null || specializes(coerceMeths.head.symtype, best.symtype)))
+ best = coerceMeths.head;
+ coerceMeths = coerceMeths.tail
+ }
+ if (best != null) {
+ coerceMeths = getCoerceMeths;
+ while (!coerceMeths.isEmpty) {
+ if (coerceMeths.head != best &&
+ isApplicable(coerceMeths.head.symtype, argtypes, pt, false) &&
+ !(specializes(best.symtype, coerceMeths.head.symtype) &&
+ !specializes(coerceMeths.head.symtype, best.symtype)))
+ throw new Type$Error(
+ "ambiguous coerce,\n" +
+ "both " + coerceMeths.head.sym + ": " + coerceMeths.head.symtype + coerceMeths.head.sym.locationString() + "\n" +
+ "and " + best.sym + ": " + best.symtype + best.sym.locationString() + "\nmap argument type " +
+ tp + " to expected type " + pt);
+ coerceMeths = coerceMeths.tail;
+ }
+ }
+ best
+ }
+}
}
+
diff --git a/sources/scalac/ast/TreeInfo.java b/sources/scalac/ast/TreeInfo.java
index 2aa95f401c..b66b7d2357 100644
--- a/sources/scalac/ast/TreeInfo.java
+++ b/sources/scalac/ast/TreeInfo.java
@@ -191,6 +191,31 @@ public class TreeInfo {
}
}
+ /** The symbol with name `name' imported from import clause `tree'.
+ */
+ public static Symbol importedSymbol(Tree tree, Name name) {
+ switch (tree) {
+ case Import(Tree expr, Name[] selectors):
+ Type pre = tree.symbol().type();
+ boolean renamed = false;
+ for (int i = 0; i < selectors.length; i = i + 2) {
+ if (i + 1 < selectors.length && name.toTermName() == selectors[i + 1]) {
+ if (name.isTypeName())
+ return pre.lookupNonPrivate(selectors[i].toTypeName());
+ else
+ return pre.lookupNonPrivate(selectors[i]);
+ } else if (name.toTermName() == selectors[i]) {
+ renamed = true;
+ } else if (selectors[i] == Names.IMPORT_WILDCARD && !renamed) {
+ return pre.lookupNonPrivate(name);
+ }
+ }
+ return Symbol.NONE;
+ default:
+ throw new ApplicationError();
+ }
+ }
+
/** returns true if the tree is a sequence-valued pattern.
* precondition: tree is a pattern.
diff --git a/sources/scalac/util/Names.java b/sources/scalac/util/Names.java
index 9824c2cf9a..ac8917a752 100644
--- a/sources/scalac/util/Names.java
+++ b/sources/scalac/util/Names.java
@@ -213,6 +213,7 @@ public class Names {
public static final Name throw_ = Name.fromString("throw");
public static final Name true_ = Name.fromString("true");
public static final Name update = Name.fromString("update");
+ public static final Name view = Name.fromString("view");
public static final Name tag = Name.fromString("$tag");