diff options
author | Martin Odersky <odersky@gmail.com> | 2004-03-26 13:35:11 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2004-03-26 13:35:11 +0000 |
commit | 13005976275b6f629b9cce2138df189a532f43c3 (patch) | |
tree | 474c767cd24487286e7bf6d384187778422477f8 | |
parent | ae8b367bfe69cd28e1f07c628c713c52c5589c9b (diff) | |
download | scala-13005976275b6f629b9cce2138df189a532f43c3.tar.gz scala-13005976275b6f629b9cce2138df189a532f43c3.tar.bz2 scala-13005976275b6f629b9cce2138df189a532f43c3.zip |
*** empty log message ***
-rw-r--r-- | config/list/scalac.lst | 2 | ||||
-rw-r--r-- | sources/scala/tools/scalac/ast/parser/Parser.scala | 18 | ||||
-rw-r--r-- | sources/scala/tools/scalac/ast/parser/Tokens.scala | 2 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Analyzer.scala | 118 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Coerce.scala | 15 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Context.scala | 40 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Infer.scala | 224 | ||||
-rw-r--r-- | sources/scala/tools/util/PlainFile.java | 19 | ||||
-rw-r--r-- | sources/scala/tools/util/SourceFile.java | 9 | ||||
-rw-r--r-- | sources/scalac/Global.java | 39 | ||||
-rw-r--r-- | sources/scalac/symtab/Modifiers.java | 1 | ||||
-rw-r--r-- | sources/scalac/symtab/Symbol.java | 3 | ||||
-rw-r--r-- | sources/scalac/symtab/Type.java | 2 | ||||
-rw-r--r-- | test/files/pos/testcast.scala | 23 |
14 files changed, 372 insertions, 143 deletions
diff --git a/config/list/scalac.lst b/config/list/scalac.lst index 131741ca79..ff3db6d15b 100644 --- a/config/list/scalac.lst +++ b/config/list/scalac.lst @@ -31,7 +31,7 @@ typechecker/DeSugarize.scala typechecker/ImportList.scala typechecker/Infer.scala typechecker/Substituter.scala -typechecker/Coerce.scala +typechecker/View.scala util/NewArray.scala 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); } } diff --git a/test/files/pos/testcast.scala b/test/files/pos/testcast.scala new file mode 100644 index 0000000000..6482ed0a6d --- /dev/null +++ b/test/files/pos/testcast.scala @@ -0,0 +1,23 @@ +package test; + +class A; + +class B { + def foo: int = 1; +} + +class B1 { + def bar: int = 1 +} + +object C { + def view(x: B): B1 = null; +} +object Test { + import C.view; + + val b: B = null; + + System.out.println(C.view(b).bar); + System.out.println(b.bar); +} |