summaryrefslogtreecommitdiff
path: root/sources
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2004-03-26 13:35:11 +0000
committerMartin Odersky <odersky@gmail.com>2004-03-26 13:35:11 +0000
commit13005976275b6f629b9cce2138df189a532f43c3 (patch)
tree474c767cd24487286e7bf6d384187778422477f8 /sources
parentae8b367bfe69cd28e1f07c628c713c52c5589c9b (diff)
downloadscala-13005976275b6f629b9cce2138df189a532f43c3.tar.gz
scala-13005976275b6f629b9cce2138df189a532f43c3.tar.bz2
scala-13005976275b6f629b9cce2138df189a532f43c3.zip
*** empty log message ***
Diffstat (limited to 'sources')
-rw-r--r--sources/scala/tools/scalac/ast/parser/Parser.scala18
-rw-r--r--sources/scala/tools/scalac/ast/parser/Tokens.scala2
-rw-r--r--sources/scala/tools/scalac/typechecker/Analyzer.scala118
-rw-r--r--sources/scala/tools/scalac/typechecker/Coerce.scala15
-rw-r--r--sources/scala/tools/scalac/typechecker/Context.scala40
-rw-r--r--sources/scala/tools/scalac/typechecker/Infer.scala224
-rw-r--r--sources/scala/tools/util/PlainFile.java19
-rw-r--r--sources/scala/tools/util/SourceFile.java9
-rw-r--r--sources/scalac/Global.java39
-rw-r--r--sources/scalac/symtab/Modifiers.java1
-rw-r--r--sources/scalac/symtab/Symbol.java3
-rw-r--r--sources/scalac/symtab/Type.java2
12 files changed, 348 insertions, 142 deletions
diff --git a/sources/scala/tools/scalac/ast/parser/Parser.scala b/sources/scala/tools/scalac/ast/parser/Parser.scala
index a295c94181..d389c0f909 100644
--- a/sources/scala/tools/scalac/ast/parser/Parser.scala
+++ b/sources/scala/tools/scalac/ast/parser/Parser.scala
@@ -1491,15 +1491,23 @@ class Parser(unit: Unit) {
typeBounds(s.pos, mods, ident())
}
- /** TypeBounds ::= [`>:' Type] [`<:' Type]
+ /** TypeBounds ::= [`>:' Type] [`<:' Type | `<+' Type]
*/
- def typeBounds(pos: int, mods: int, name: Name): Tree = {
+ def typeBounds(pos: int, _mods: int, name: Name): Tree = {
+ var mods = _mods;
val lobound =
if (s.token == SUPERTYPE) { s.nextToken(); typ() }
else scalaDot(pos, Names.All.toTypeName());
val hibound =
- if (s.token == SUBTYPE) { s.nextToken(); typ() }
- else scalaDot(pos, Names.Any.toTypeName());
+ if (s.token == SUBTYPE) {
+ s.nextToken();
+ typ()
+ } else if ((mods & Modifiers.PARAM) != 0 && s.token == VIEWBOUND) {
+ mods = mods | Modifiers.VIEWBOUND;
+ s.nextToken();
+ typ()
+ } else
+ scalaDot(pos, Names.Any.toTypeName());
make.AbsTypeDef(pos, mods, name.toTypeName(), hibound, lobound)
}
@@ -1804,7 +1812,7 @@ class Parser(unit: Unit) {
case EQUALS =>
s.nextToken();
make.AliasTypeDef(pos, mods, name, Tree.AbsTypeDef_EMPTY_ARRAY, typ())
- case SUPERTYPE | SUBTYPE | SEMI | COMMA | RBRACE =>
+ case SUPERTYPE | SUBTYPE | VIEWBOUND | SEMI | COMMA | RBRACE =>
typeBounds(pos, mods | Modifiers.DEFERRED, name)
case _ =>
syntaxError("`=', `>:', or `<:' expected", true)
diff --git a/sources/scala/tools/scalac/ast/parser/Tokens.scala b/sources/scala/tools/scalac/ast/parser/Tokens.scala
index e7a1f6875c..fad884f6be 100644
--- a/sources/scala/tools/scalac/ast/parser/Tokens.scala
+++ b/sources/scala/tools/scalac/ast/parser/Tokens.scala
@@ -91,6 +91,7 @@ object Tokens {
val SUPERTYPE = 70;
val HASH = 71;
val AT = 72;
+ val VIEWBOUND = 73;
/** parenthesis */
val LPAREN = 90;
@@ -204,6 +205,7 @@ object Tokens {
enterKeyword("<-", LARROW);
enterKeyword("<:", SUBTYPE);
enterKeyword(">:", SUPERTYPE);
+ enterKeyword("<+", VIEWBOUND);
enterKeyword("#", HASH);
enterKeyword("@", AT);
diff --git a/sources/scala/tools/scalac/typechecker/Analyzer.scala b/sources/scala/tools/scalac/typechecker/Analyzer.scala
index 419da47a53..aaadcfed99 100644
--- a/sources/scala/tools/scalac/typechecker/Analyzer.scala
+++ b/sources/scala/tools/scalac/typechecker/Analyzer.scala
@@ -48,7 +48,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
val definitions = global.definitions;
val infer = new scala.tools.scalac.typechecker.Infer(this) {
- override def getCoerceMeths = { context.coerceMeths; }
+ override def getContextViewMeths = { context.viewMeths; }
}
val desugarize = new DeSugarize(make, copy, gen, infer, global);
val constfold = new ConstantFolder(global);
@@ -632,6 +632,35 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
sym.getType().isInstanceOf[Type$PolyType] &&
sym.typeParams().length == 0;
+// Views -----------------------------------------------------------------------
+
+ private def applyView(v: View, tree: Tree): Tree = {
+ val viewFn = {
+ val qual1 = v.qual.duplicate();
+ qual1.pos = tree.pos;
+ val viewType = checkAccessible(
+ tree.pos, v.sym, v.symtype, qual1, qual1.getType());
+ make.Select(tree.pos, qual1, v.sym.name)
+ .setSymbol(v.sym).setType(viewType)
+ }
+ gen.Apply(viewFn, NewArray.Tree(tree.setType(tree.getType().singleDeref())))
+ }
+
+ def addView(tparam: Symbol): unit = {
+ if (tparam.info().symbol() != definitions.ANY_CLASS) {
+ val viewSym =
+ context.owner.newTerm(tparam.pos, SYNTHETIC | PARAM, Names.view);
+ val viewParam =
+ viewSym.newTerm(tparam.pos, SYNTHETIC | PARAM, desugarize.getvar());
+ viewParam.setInfo(tparam.getType());
+ viewSym.setInfo(
+ new Type$MethodType(NewArray.Symbol(viewParam), tparam.info()));
+ global.viewOfTypeParam.put(tparam, viewSym);
+ context.scope.enterOrOverload(viewSym);
+ System.out.println("view: " + viewSym + ":" + viewSym.getType());//debug
+ }
+ }
+
// Contexts -------------------------------------------------------------------
/** Push new context associated with given tree, owner, and scope on stack.
@@ -645,7 +674,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
def popContext(): unit =
context = context.outer;
- // Lazy Types ------------------------------------------------------------------
+// Lazy Types ------------------------------------------------------------------
/** A lazy type which, when forced returns the type of a symbol defined
* in `tree'.
@@ -1036,6 +1065,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
//necessary since tsyms might have been unpickled
tparams(i).setSymbol(tsyms(i));
context.scope.enter(tsyms(i));
+ //addView(tsyms(i));
i = i + 1
}
}
@@ -1524,25 +1554,12 @@ 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 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);
- }
+ val v = infer.bestView(tree.getType(), pt);
+ if (v != null) return adapt(applyView(v, tree), mode, pt);
// todo: remove
val coerceMeth: Symbol = tree.getType().lookup(Names.coerce);
if (coerceMeth != Symbol.NONE) {
- val coerceType: Type = checkAccessible(
+ val coerceType = checkAccessible(
tree.pos, coerceMeth, tree.getType().memberType(coerceMeth),
tree, tree.getType());
val tree1 = make.Select(tree.pos, tree, Names.coerce)
@@ -1676,40 +1693,49 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
uninst = tparams;
case _ =>
}
- val sym: Symbol = qual.getType().lookup(name);
+ var sym: Symbol = qual.getType().lookup(name);
if (sym.kind == NONE) {
- //System.out.println(qual.getType() + " has members " + qual.getType().members());//DEBUG
- error(tree.pos,
+ if (name != Names.view) {
+ val v = infer.bestView(qual.getType(), name);
+ if (v != null) {
+ qual = applyView(v, qual);
+ sym = qual.getType().lookup(name);
+ assert(sym.kind != NONE);
+ } else {
+ //System.out.println(qual.getType() + " has members " + qual.getType().members());//DEBUG
+ return error(
+ tree.pos,
decode(name) + " is not a member of " + qual.getType().widen());
- } else {
- val qualtype =
- if (qual.isInstanceOf[Tree$Super]) context.enclClass.owner.thisType()
- else qual.getType();
- var symtype: Type =
- (if (sym.isType()) sym.typeConstructor() else sym.getType())
- .asSeenFrom(qualtype, sym.owner());
- if (symtype == Type.NoType)
- return error(tree.pos, "not found: " + decode(name));
- else
- symtype = checkAccessible(tree.pos, sym, symtype, qual, qualtype);
- //System.out.println(sym.name + ":" + symtype);//DEBUG
- if (uninst.length != 0) {
- symtype match {
- case Type$PolyType(tparams, restype) =>
- symtype = new Type$PolyType(tparams, new Type$PolyType(uninst, restype));
- case _ =>
- symtype = new Type$PolyType(uninst, symtype);
}
}
- //System.out.println(qual.getType() + ".member: " + sym + ":" + symtype);//DEBUG
- val tree1: Tree = tree match {
- case Tree$Select(_, _) =>
- copy.Select(tree, sym, qual)
- case Tree$SelectFromType(_, _) =>
- copy.SelectFromType(tree, sym, qual)
+ }
+ val qualtype =
+ if (qual.isInstanceOf[Tree$Super]) context.enclClass.owner.thisType()
+ else qual.getType();
+ var symtype: Type =
+ (if (sym.isType()) sym.typeConstructor() else sym.getType())
+ .asSeenFrom(qualtype, sym.owner());
+ if (symtype == Type.NoType)
+ return error(tree.pos, "not found: " + decode(name));
+ else
+ symtype = checkAccessible(tree.pos, sym, symtype, qual, qualtype);
+ //System.out.println(sym.name + ":" + symtype);//DEBUG
+ if (uninst.length != 0) {
+ symtype match {
+ case Type$PolyType(tparams, restype) =>
+ symtype = new Type$PolyType(tparams, new Type$PolyType(uninst, restype));
+ case _ =>
+ symtype = new Type$PolyType(uninst, symtype);
}
- mkStable(tree1.setType(symtype), qualtype, mode, pt)
}
+ //System.out.println(qual.getType() + ".member: " + sym + ":" + symtype);//DEBUG
+ val tree1: Tree = tree match {
+ case Tree$Select(_, _) =>
+ copy.Select(tree, sym, qual)
+ case Tree$SelectFromType(_, _) =>
+ copy.SelectFromType(tree, sym, qual)
+ }
+ mkStable(tree1.setType(symtype), qualtype, mode, pt)
}
/** Attribute a pattern matching expression where `pattpe' is the
diff --git a/sources/scala/tools/scalac/typechecker/Coerce.scala b/sources/scala/tools/scalac/typechecker/Coerce.scala
deleted file mode 100644
index 485e8e519e..0000000000
--- a/sources/scala/tools/scalac/typechecker/Coerce.scala
+++ /dev/null
@@ -1,15 +0,0 @@
-/* ____ ____ ____ ____ ______ *\
-** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
-** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
-** /_____/\____/\___/\____/____/ **
-**
-** $Id$
-\* */
-import scalac.symtab._;
-import scalac.ast._;
-
-package scala.tools.scalac.typechecker {
-
-case class Coerce(sym: Symbol, symtype: Type, qual: Tree, context: Context);
-
-}
diff --git a/sources/scala/tools/scalac/typechecker/Context.scala b/sources/scala/tools/scalac/typechecker/Context.scala
index a245aeb437..f37b21ee2e 100644
--- a/sources/scala/tools/scalac/typechecker/Context.scala
+++ b/sources/scala/tools/scalac/typechecker/Context.scala
@@ -13,7 +13,7 @@ package scala.tools.scalac.typechecker {
object Context {
val NONE = new Context();
- NONE.coerceCache = List();
+ NONE.viewCache = List();
}
class Context {
@@ -29,7 +29,7 @@ class Context {
// 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 viewCache: List[View] = null; // View symbols visible in scope
var infer: Infer = null; // Type inferencer
def this(tree: Tree, owner: Symbol, scope: Scope, outer: Context) = {
@@ -68,37 +68,41 @@ class Context {
outer.isTopLevel()
}
- def coerceMeths: List[Coerce] = {
+ def viewMeths: List[View] = {
- def addCoerce(sym: Symbol, symtype: Type, qual: Tree): unit = symtype match {
+ def addView(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;
+ var i = alts.length - 1;
+ while (i >= 0) {
+ addView(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);
+ /*
+ def isUnShadowed(view: View) =
+ view.context == this || !infer.specializes(view.symtype, symtype);
+ */
+ if (viewCache.forall(v => v.sym != sym)) {
+ val v = View(sym, symtype, qual, this);
+ System.out.println("VIEW " + sym + ":" + symtype + " " + qual);//debug
+ viewCache = v :: viewCache;//.filter(isUnShadowed);
+ }
}
- if (coerceCache == null) {
- coerceCache = outer.coerceMeths;
+ if (viewCache == null) {
+ viewCache = outer.viewMeths;
val e = scope.lookupEntry(Names.view);
if (e.owner == scope && e.sym.kind == VAL)
- addCoerce(e.sym, e.sym.getType(), Tree.Empty);
+ addView(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());
+ addView(sym, imp.importType().memberType(sym), imp.importPrefix());
imp = imp.prev;
}
}
- coerceCache
+ viewCache
}
}
}
diff --git a/sources/scala/tools/scalac/typechecker/Infer.scala b/sources/scala/tools/scalac/typechecker/Infer.scala
index 74ed2d8cad..38621cab7a 100644
--- a/sources/scala/tools/scalac/typechecker/Infer.scala
+++ b/sources/scala/tools/scalac/typechecker/Infer.scala
@@ -14,6 +14,8 @@ import scalac.ApplicationError;
import scalac.util._;
import scalac.ast._;
import scalac.symtab._;
+import scala.collection.mutable.HashMap;
+import scala.tools.util.Position;
import scala.tools.scalac.util.NewArray;
@@ -28,9 +30,66 @@ 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 */
+// View generator, overridable */
- def getCoerceMeths: List[Coerce] = List();
+ def getContextViewMeths: List[View] = List();
+
+ private def getViews(tp: Type): List[View] = {
+ memberViews(tp) ::: getContextViewMeths;
+ }
+
+ val memberViewCache = new HashMap[Symbol, List[View]];
+
+// private def memberViews(tp: Type): List[View] = List();
+
+ private def memberViews(tp: Type): List[View] = {
+ val tpsym = tp.widen().symbol();
+ memberViewCache.get(tpsym) match {
+ case Some(vs) => vs
+ case None =>
+ var vs = companionObjViews(tp, tpsym);
+ val ps = tpsym.parents();
+ var i = ps.length - 1; while (i >= 0) {
+ vs = memberViews(ps(i)) ::: vs;
+ i = i - 1
+ }
+ memberViewCache.update(tpsym, vs);
+ vs
+ }
+ }
+
+ private def companionObjViews(tp: Type, clazz: Symbol): List[View] = {
+ if (clazz.kind == CLASS && !clazz.isModuleClass() && !clazz.isCaseClass()) {
+ var obj = clazz.owner().info().lookupNonPrivate(clazz.name.toTermName());
+ //System.out.println("comp obj view " + tp + " " + obj);//DEBUG
+ obj.getType() match {
+ case Type$OverloadedType(alts, alttypes) =>
+ var i = 0; while (i < alts.length) {
+ if (alts(i).isModule()) obj = alts(i);
+ i = i + 1
+ }
+ case _ =>
+ }
+ if (obj.isModule()) {
+ val qual = gen.mkRef(Position.NOPOS, tp.prefix(), obj);
+ val viewsym = obj.info().lookupNonPrivate(Names.view);
+ if (viewsym.kind == VAL) {
+ obj.getType().memberType(viewsym) match {
+ case Type$OverloadedType(alts, alttypes) =>
+ var i = alttypes.length - 1;
+ var vs: List[View] = List();
+ while (i >= 0) {
+ vs = View(alts(i), alttypes(i), qual, Context.NONE) :: vs;
+ i = i - 1
+ }
+ vs
+ case viewtype =>
+ List(View(viewsym, viewtype, qual, Context.NONE))
+ }
+ } else List()
+ } else List()
+ } else List()
+ }
// Error messages -------------------------------------------------------------
@@ -455,11 +514,14 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
/** Is normalized type `tp' a subtype of prototype `pt'?
*/
- def isCompatible(tp: Type, pt: Type): boolean = {
- def canCoerce(tp: Type): boolean = tp match {
+ def isCompatible(tp: Type, pt: Type): boolean =
+ isCompatible(tp, pt, true);
+
+ def isCompatible(tp: Type, pt: Type, coercible: boolean): boolean = {
+ def canView(tp: Type): boolean = tp match {
case Type$OverloadedType(_, alttypes) =>
var i = 0;
- while (i < alttypes.length && !canCoerce(alttypes(i))) i = i + 1;
+ while (i < alttypes.length && !canView(alttypes(i))) i = i + 1;
i < alttypes.length
case Type$PolyType(tparams, restype) if tparams.length == 0 =>
restype.isSubType(pt)
@@ -468,25 +530,28 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
}
val tp1 = normalize(tp);
if (tp1.isSubType(pt)) true
- else {
+ else if (coercible) {
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
+ var viewMeths = getViews(tp1);
+ while (!viewMeths.isEmpty && !isApplicable(viewMeths.head.symtype, argtypes, pt, false))
+ viewMeths = viewMeths.tail;
+ if (!viewMeths.isEmpty) true
// todo: remove
else {
val coerceMeth: Symbol = tp1.lookup(Names.coerce);
- coerceMeth.kind != NONE && canCoerce(tp1.memberType(coerceMeth));
+ coerceMeth.kind != NONE && canView(tp1.memberType(coerceMeth));
}
- }
+ } else 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;
+ def isCompatible(tps: Array[Type], pts: Array[Type]): boolean =
+ isCompatible(tps, pts, true);
+
+ def isCompatible(tps: Array[Type], pts: Array[Type], coercible: boolean): boolean = {
+ var i = 0; while (i < tps.length) {
+ if (!isCompatible(tps(i), pts(i), coercible)) return false;
i = i + 1
- }}
+ }
true
}
@@ -511,10 +576,14 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
* If no minimal type variables exist that make the
* instantiated type a subtype of `pt', return `null'.
*/
- private def exprTypeArgs(tparams: Array[Symbol], restype: Type, pt: Type): Array[Type] = {
+ private def exprTypeArgs(tparams: Array[Symbol], restype: Type, pt: Type): Array[Type] =
+ exprTypeArgs(tparams, restype, pt, true);
+
+ private def exprTypeArgs(tparams: Array[Symbol], restype: Type,
+ pt: Type, coercible: boolean): Array[Type] = {
val tvars: Array[Type] = freshVars(tparams);
val insttype: Type = restype.subst(tparams, tvars);
- if (isCompatible(insttype, pt)) {
+ if (isCompatible(insttype, pt, coercible)) {
try {
val restype1 = normalize(restype);
{ var i = 0; while (i < tvars.length) {
@@ -572,7 +641,10 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
* Undetermined type arguments are represented by `definitions.ALL_TYPE'.
* No check that inferred parameters conform to their bounds is made here.
*/
- private def methTypeArgs(tparams: Array[Symbol], params: Array[Symbol], argtypes: Array[Type], restp: Type, pt: Type, needToSucceed: boolean): Array[Type] = {
+ private def methTypeArgs(tparams: Array[Symbol], params: Array[Symbol],
+ argtypes: Array[Type], restp: Type,
+ pt: Type,
+ needToSucceed: boolean, coercible: boolean): Array[Type] = {
//System.out.println("methTypeArgs, tparams = " + ArrayApply.toString(tparams) + ", params = " + ArrayApply.toString(params) + ", type(params) = " + ArrayApply.toString(Symbol.type(params)) + ", argtypes = " + ArrayApply.toString(argtypes));//DEBUG
val tvars: Array[Type] = freshVars(tparams);
@@ -585,7 +657,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
// check first whether type variables can be fully defined from
// expected result type.
- if (!isCompatible(restp.subst(tparams, tvars), pt)) {
+ if (!isCompatible(restp.subst(tparams, tvars), pt, coercible)) {
if (needToSucceed)
throw new NoInstance("result type " + restp +
" is incompatible with expected type " + pt);
@@ -600,7 +672,9 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
// Then define remaining type variables from argument types.
var i = 0;
while (i < argtypes.length) {
- if (!isCompatible(argtypes(i).widen().subst(tparams, tvars), formals(i).subst(tparams, tvars))) {
+ if (!isCompatible(argtypes(i).widen().subst(tparams, tvars),
+ formals(i).subst(tparams, tvars),
+ coercible)) {
if (needToSucceed) {
if (global.explaintypes) {
Type.explainSwitch = true;
@@ -728,7 +802,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
case Type$MethodType(params, restpe) =>
var targs: Array[Type] = _;
try {
- targs = methTypeArgs(tparams, params, argtypes, restpe, pt, true);
+ targs = methTypeArgs(tparams, params, argtypes, restpe, pt, true, false);
} catch {
case ex: NoInstance =>
throw new Type$Error(
@@ -808,16 +882,46 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
// sequences ? List( a* )
val formals: Array[Type] = formalTypes(params, argtypes.length);
formals.length == argtypes.length &&
- (if (coercible) isCompatible(argtypes, formals) && isCompatible(restpe, pt)
- else Type.isSubType(argtypes, formals) && restpe.isSubType(pt));
+ isCompatible(argtypes, formals, coercible) &&
+ isCompatible(restpe, pt, coercible);
+ case Type$PolyType(tparams, Type$MethodType(params, restpe)) =>
+ try {
+ val targs: Array[Type] = methTypeArgs(
+ tparams, params, argtypes, restpe, pt, false, coercible);
+ if (targs != null) {
+ val uninstantiated: Array[Symbol] = normalizeArgs(targs, tparams);
+ isWithinBounds(tparams, targs) &&
+ exprTypeArgs(uninstantiated,
+ restpe.subst(tparams, targs), pt,
+ coercible) != null;
+ } else {
+ false
+ }
+ } catch {
+ case ex: NoInstance => false
+ }
+ case _ =>
+ false
+ }
+
+ /** Is function type `ftpe' applicable to `argtypes' and
+ * does its result contain a member with name `name'?
+ */
+ def isApplicable(ftpe: Type, argtypes: Array[Type], name: Name, coercible: boolean): boolean = ftpe match {
+ case Type$MethodType(params, restpe) =>
+ // sequences ? List( a* )
+ val formals: Array[Type] = formalTypes(params, argtypes.length);
+ formals.length == argtypes.length &&
+ isCompatible(argtypes, formals, coercible) &&
+ restpe.lookup(name).kind != NONE;
case Type$PolyType(tparams, Type$MethodType(params, restpe)) =>
try {
val targs: Array[Type] = methTypeArgs(
- tparams, params, argtypes, restpe, pt, false);
+ tparams, params, argtypes, restpe, Type.AnyType, false, coercible);
if (targs != null) {
val uninstantiated: Array[Symbol] = normalizeArgs(targs, tparams);
isWithinBounds(tparams, targs) &&
- exprTypeArgs(uninstantiated, restpe.subst(tparams, targs), pt) != null;
+ restpe.subst(tparams, targs).lookup(name) != NONE;
} else {
false
}
@@ -961,31 +1065,61 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
}
}
- /** return coerce which best matches argument type `tp' and expected type `pt'.
+ /** return view which best matches argument type `tp' and has `name' as member.
+ */
+ def bestView(tp: Type, name: Name): View = {
+ var best: View = null;
+ var viewMeths = getViews(tp);
+ val argtypes = NewArray.Type(tp);
+ while (!viewMeths.isEmpty) {
+ if (isApplicable(viewMeths.head.symtype, argtypes, name, false) &&
+ (best == null || specializes(viewMeths.head.symtype, best.symtype)))
+ best = viewMeths.head;
+ viewMeths = viewMeths.tail
+ }
+ if (best != null) {
+ viewMeths = getViews(tp);
+ while (!viewMeths.isEmpty) {
+ if (viewMeths.head != best &&
+ isApplicable(viewMeths.head.symtype, argtypes, name, false) &&
+ !(specializes(best.symtype, viewMeths.head.symtype) &&
+ !specializes(viewMeths.head.symtype, best.symtype)))
+ throw new Type$Error(
+ "ambiguous view,\n" +
+ "both " + viewMeths.head.sym + ": " + viewMeths.head.symtype + viewMeths.head.sym.locationString() + "\n" +
+ "and " + best.sym + ": " + best.symtype + best.sym.locationString() + "\nadd member `" +
+ name + "' to argument type " + tp.widen());
+ viewMeths = viewMeths.tail;
+ }
+ }
+ best
+ }
+
+ /** return view which best matches argument type `tp' and expected type `pt'.
*/
- def bestCoerce(tp: Type, pt: Type): Coerce = {
- var best: Coerce = null;
- var coerceMeths = getCoerceMeths;
+ def bestView(tp: Type, pt: Type): View = {
+ var best: View = null;
+ var viewMeths = getViews(tp);
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
+ while (!viewMeths.isEmpty) {
+ if (isApplicable(viewMeths.head.symtype, argtypes, pt, false) &&
+ (best == null || specializes(viewMeths.head.symtype, best.symtype)))
+ best = viewMeths.head;
+ viewMeths = viewMeths.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)))
+ viewMeths = getViews(tp);
+ while (!viewMeths.isEmpty) {
+ if (viewMeths.head != best &&
+ isApplicable(viewMeths.head.symtype, argtypes, pt, false) &&
+ !(specializes(best.symtype, viewMeths.head.symtype) &&
+ !specializes(viewMeths.head.symtype, best.symtype)))
throw new Type$Error(
- "ambiguous coerce,\n" +
- "both " + coerceMeths.head.sym + ": " + coerceMeths.head.symtype + coerceMeths.head.sym.locationString() + "\n" +
+ "ambiguous view,\n" +
+ "both " + viewMeths.head.sym + ": " + viewMeths.head.symtype + viewMeths.head.sym.locationString() + "\n" +
"and " + best.sym + ": " + best.symtype + best.sym.locationString() + "\nmap argument type " +
- tp + " to expected type " + pt);
- coerceMeths = coerceMeths.tail;
+ tp.widen() + " to expected type " + pt);
+ viewMeths = viewMeths.tail;
}
}
best
diff --git a/sources/scala/tools/util/PlainFile.java b/sources/scala/tools/util/PlainFile.java
index 6684774038..aee80cb52f 100644
--- a/sources/scala/tools/util/PlainFile.java
+++ b/sources/scala/tools/util/PlainFile.java
@@ -66,6 +66,25 @@ public class PlainFile extends AbstractFile {
return file;
}
+
+ public int hashCode() {
+ try {
+ return file.getCanonicalPath().hashCode();
+ } catch (IOException ex) {
+ return 0;
+ }
+ }
+
+ public boolean equals(Object that) {
+ try {
+ return that instanceof PlainFile &&
+ file.getCanonicalPath().equals(((PlainFile) that).file.getCanonicalPath());
+ } catch (IOException ex) {
+ return that instanceof PlainFile &&
+ file.getAbsolutePath().equals(((PlainFile) that).file.getAbsolutePath());
+ }
+ }
+
/** Is this abstract file a directory? */
public boolean isDirectory() {
return file.isDirectory();
diff --git a/sources/scala/tools/util/SourceFile.java b/sources/scala/tools/util/SourceFile.java
index 403b3011ff..79964d4b2e 100644
--- a/sources/scala/tools/util/SourceFile.java
+++ b/sources/scala/tools/util/SourceFile.java
@@ -96,6 +96,15 @@ public class SourceFile {
return file.toString();
}
+ public int hashCode() {
+ return file.hashCode();
+ }
+
+ public boolean equals(Object that) {
+ return that instanceof SourceFile &&
+ file.equals(((SourceFile) that).file);
+ }
+
//########################################################################
// Private Functions
diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java
index d2d0df060d..a45a1aeac8 100644
--- a/sources/scalac/Global.java
+++ b/sources/scalac/Global.java
@@ -122,16 +122,27 @@ public abstract class Global {
*/
public final Map/*<Symbol, String>*/ mapSymbolComment = new HashMap();
+ /** views associated with (upper-bounded) type parameters
+ */
+ public final Map/*<Symbol, Symbol>*/ viewOfTypeParam = new HashMap();
+
+ /** Pickled info of top-level symbols
+ */
public final Map/*<Symbol, Pickle>*/ symdata = new HashMap();
+
/** The compiler command arguments
*/
public final CompilerCommand args;
- /** The set of currenttly compiled top-level symbols
+ /** The set of currently compiled top-level symbols
*/
public HashMap/*<Symbol,Sourcefile>*/ compiledNow = new HashMap();
+ /** The set of already compiled sourcefiles
+ */
+ public HashSet/*<SourceFile>*/ compiledUnits = new HashSet();
+
/** the current phase
*/
public Phase currentPhase;
@@ -334,7 +345,9 @@ public abstract class Global {
List units = new ArrayList(files.length);
for (int i = 0; i < files.length; i++) {
try {
- units.add(new Unit(this, getSourceFile(files[i]), console));
+ SourceFile source = getSourceFile(files[i]);
+ units.add(new Unit(this, source, console));
+ compiledUnits.add(source);
} catch (IOException exception) {
error(exception.getMessage());
}
@@ -353,6 +366,7 @@ public abstract class Global {
public void compile(String filename, String input, boolean console) {
reporter.resetCounters();
SourceFile source = getSourceFile(filename, input);
+ compiledUnits.add(source);
units = new Unit[]{new Unit(this, source, console)};
compile();
}
@@ -394,15 +408,18 @@ public abstract class Global {
/** Compiles an additional source file. */
public void compileLate(SourceFile source, boolean mixinOnly) {
- Unit unit = new Unit(this, source, false, mixinOnly);
- Phase backup = currentPhase;
- // !!! add code to print/skip/graph as in compile
- currentPhase = PHASE.PARSER.phase();
- PHASE.PARSER.phase().apply(new Unit[] {unit});
- currentPhase = PHASE.ANALYZER.phase();
- ((AnalyzerPhase)PHASE.ANALYZER.phase()).lateEnter(unit);
- // !!! add code for later phases?
- currentPhase = backup;
+ if (!compiledUnits.contains(source)) {
+ compiledUnits.add(source);
+ Unit unit = new Unit(this, source, false, mixinOnly);
+ Phase backup = currentPhase;
+ // !!! add code to print/skip/graph as in compile
+ currentPhase = PHASE.PARSER.phase();
+ PHASE.PARSER.phase().apply(new Unit[] {unit});
+ currentPhase = PHASE.ANALYZER.phase();
+ ((AnalyzerPhase)PHASE.ANALYZER.phase()).lateEnter(unit);
+ // !!! add code for later phases?
+ currentPhase = backup;
+ }
}
private void print() {
diff --git a/sources/scalac/symtab/Modifiers.java b/sources/scalac/symtab/Modifiers.java
index 22d7ed3e21..afe215ea3d 100644
--- a/sources/scalac/symtab/Modifiers.java
+++ b/sources/scalac/symtab/Modifiers.java
@@ -31,6 +31,7 @@ public interface Modifiers {
int JAVA = 0x00001000; // symbol was defined by a Java class
int MODUL = 0x00002000; // symbol is module or class implementing a module
int MUTABLE = 0x00004000; // symbol is a mutable variable.
+ int VIEWBOUND = 0x00004000; // type symbol has a <+ bound.
int PARAM = 0x00008000; // symbol is a (type) parameter to a method
int INITIALIZED = 0x00010000; // symbol's definition is complete
diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java
index 2df07c6b34..42a9606e91 100644
--- a/sources/scalac/symtab/Symbol.java
+++ b/sources/scalac/symtab/Symbol.java
@@ -1370,7 +1370,8 @@ public abstract class Symbol implements Modifiers, Kinds {
if (owner.kind == CLASS &&
!owner.isAnonymousClass() && !owner.isCompoundSym() ||
Global.instance.debug)
- return " in " + owner;
+ return " in " +
+ (owner.isModuleClass() ? ((ClassSymbol) owner).module() : owner);
else
return "";
}
diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java
index 2c15e6a58c..7a1b8cb3db 100644
--- a/sources/scalac/symtab/Type.java
+++ b/sources/scalac/symtab/Type.java
@@ -3180,7 +3180,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags {
return UNBOXEDARRAYtpe
^ (elemtp.hashCode() * 41);
default:
- throw new ApplicationError();
+ throw new ApplicationError("bad type for hashCode: " + this);
}
}