diff options
author | Martin Odersky <odersky@gmail.com> | 2004-04-01 14:22:48 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2004-04-01 14:22:48 +0000 |
commit | bce606fb00b2ab5af4a5913cd7d1c72116bd8566 (patch) | |
tree | 7c60a4746a6090b95b127722a0af0ef7bdbdaffa | |
parent | 6e1747c335587f75470d10d8ed21e0060c6e436f (diff) | |
download | scala-bce606fb00b2ab5af4a5913cd7d1c72116bd8566.tar.gz scala-bce606fb00b2ab5af4a5913cd7d1c72116bd8566.tar.bz2 scala-bce606fb00b2ab5af4a5913cd7d1c72116bd8566.zip |
*** empty log message ***
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Analyzer.scala | 153 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/DeSugarize.scala | 55 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Infer.scala | 396 | ||||
-rw-r--r-- | test/files/pos/testcast.scala | 9 |
4 files changed, 333 insertions, 280 deletions
diff --git a/sources/scala/tools/scalac/typechecker/Analyzer.scala b/sources/scala/tools/scalac/typechecker/Analyzer.scala index aaadcfed99..e1e878fb8b 100644 --- a/sources/scala/tools/scalac/typechecker/Analyzer.scala +++ b/sources/scala/tools/scalac/typechecker/Analyzer.scala @@ -48,7 +48,8 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( val definitions = global.definitions; val infer = new scala.tools.scalac.typechecker.Infer(this) { - override def getContextViewMeths = { context.viewMeths; } + override def getContext = context; + override def error(pos: int, msg: String) = Analyzer.this.error(pos, msg); } val desugarize = new DeSugarize(make, copy, gen, infer, global); val constfold = new ConstantFolder(global); @@ -223,95 +224,10 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( error(pos, ex.msg); } -// Name resolution ----------------------------------------------------------- - def decode(name: Name): String = if (name.isTypeName()) "type " + NameTransformer.decode(name); else "value " + NameTransformer.decode(name); - /** Check that `sym' is accessible as a member of tree `site' in current context. - */ - def checkAccessible(pos: int, sym: Symbol, symtype: Type, site: Tree, sitetype: Type): Type = { - //System.out.println("check acc " + sym);//DEBUG - if ((sym.owner().flags & INCONSTRUCTOR) != 0 && - !(sym.kind == TYPE && sym.isParameter()) && - site.isInstanceOf[Tree$This]) { - error(pos, "" + sym + " cannot be accessed from constructor"); - Type.ErrorType; - } else { - symtype match { - case Type$OverloadedType(alts, alttypes) => - var nacc: int = 0; - var i = 0; while (i < alts.length) { - if (isAccessible(alts(i), site, sitetype)) - nacc = nacc + 1; - i = i + 1 - } - if (nacc == 0) { - error(pos, "" + sym + " cannot be accessed in " + sitetype.widen()); - Type.ErrorType - } else { - val alts1: Array[Symbol] = new Array[Symbol](nacc); - val alttypes1: Array[Type] = new Array[Type](nacc); - nacc = 0; - var i = 0; while (i < alts.length) { - if (isAccessible(alts(i), site, sitetype)) { - alts1(nacc) = alts(i); - alttypes1(nacc) = alttypes(i); - nacc = nacc + 1; - } - i = i + 1 - } - new Type$OverloadedType(alts1, alttypes1) - } - case _ => - if (isAccessible(sym, site, sitetype)) { - symtype - } else { - error(pos, "" + sym + " cannot be accessed in " + sitetype.widen()); - Type.ErrorType - } - } - } - } - - /** Is `sym' accessible as a member of tree `site' in current context? - */ - private def isAccessible(sym: Symbol, site: Tree, sitetype: Type): boolean = { - - /** Are we inside definition of `owner'? - */ - def accessWithin(owner: Symbol): boolean = { - var c: Context = context; - while (c != Context.NONE && c.owner != owner) { - c = c.outer.enclClass; - } - c != Context.NONE; - } - - /** Is `clazz' a subclass of an enclosing class? - */ - def isSubClassOfEnclosing(clazz: Symbol): boolean = { - var c: Context = context; - while (c != Context.NONE && !clazz.isSubClass(c.owner)) { - c = c.outer.enclClass; - } - c != Context.NONE; - } - - (sym.flags & (PRIVATE | PROTECTED)) == 0 - || - {val owner = if (sym.isConstructor()) sym.constructorClass() - else sym.owner(); - accessWithin(owner) - || - ((sym.flags & PRIVATE) == 0) && - (site.isInstanceOf[Tree$Super] || - (sitetype.symbol().isSubClass(owner) && - isSubClassOfEnclosing(sitetype.symbol()))) - } - } - // Checking methods ---------------------------------------------------------- /** Check that symbol's definition is well-formed. This means: @@ -634,32 +550,10 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( // 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 - } - } + private def applyView(v: View, tree: Tree, mode: int, pt: Type): Tree = + transform( + make.Apply(tree.pos, infer.viewExpr(tree.pos, v), NewArray.Tree(tree)), + mode, pt); // Contexts ------------------------------------------------------------------- @@ -1027,6 +921,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( */ def enterSyms(stats: Array[Tree]): unit = { var i = 0; while (i < stats.length) { + stats(i) = desugarize.Definition(stats(i)); enterSym(stats(i)); i = i + 1 } @@ -1065,7 +960,6 @@ 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 } } @@ -1126,7 +1020,8 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( if (vparamSyms.length == 0) vparamSyms = NewArray.SymbolArray{Symbol.EMPTY_ARRAY}; if ((mods & CASE) != 0 && vparams.length > 0) - templ.body = desugarize.addCaseElements(templ.body, vparams(0)); + templ.body = desugarize.addCaseElements( + templ.body, vparams(vparams.length - 1)); val constrtype: Type = makeMethodType( tparamSyms, @@ -1502,7 +1397,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( // insert apply method val applyMeth: Symbol = tree.getType().lookup(Names.apply); if (applyMeth != Symbol.NONE) { - val applyType: Type = checkAccessible( + val applyType: Type = infer.checkAccessible( tree.pos, applyMeth, tree.getType().memberType(applyMeth), tree, tree.getType()); val tree1 = make.Select(tree.pos, tree, Names.apply) @@ -1554,12 +1449,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 v = infer.bestView(tree.getType(), pt); - if (v != null) return adapt(applyView(v, tree), mode, pt); + val v = infer.bestView(tree.getType(), pt, Names.EMPTY); + if (v != null) return applyView(v, tree, mode, pt); // todo: remove val coerceMeth: Symbol = tree.getType().lookup(Names.coerce); if (coerceMeth != Symbol.NONE) { - val coerceType = checkAccessible( + val coerceType = infer.checkAccessible( tree.pos, coerceMeth, tree.getType().memberType(coerceMeth), tree, tree.getType()); val tree1 = make.Select(tree.pos, tree, Names.coerce) @@ -1672,9 +1567,9 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( (if (sym.isType()) sym.typeConstructor() else sym.getType()) .asSeenFrom(pre, sym.owner()); if (qual != Tree.Empty) - symtype = checkAccessible(tree.pos, sym, symtype, qual, qual.getType()); + symtype = infer.checkAccessible(tree.pos, sym, symtype, qual, qual.getType()); else if (sym.owner().isPackageClass()) - symtype = checkAccessible(tree.pos, sym, symtype, qual, sym.owner().getType()); + symtype = infer.checkAccessible(tree.pos, sym, symtype, qual, sym.owner().getType()); if (symtype == Type.NoType) return error(tree.pos, "not found: " + decode(name)); //System.out.println(name + ":" + symtype);//DEBUG @@ -1696,9 +1591,10 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( var sym: Symbol = qual.getType().lookup(name); if (sym.kind == NONE) { if (name != Names.view) { - val v = infer.bestView(qual.getType(), name); + val v = infer.bestView(qual.getType(), Type.AnyType, name); if (v != null) { - qual = applyView(v, qual); + qual = applyView( + v, qual.setType(qual.getType().singleDeref()), EXPRmode, Type.AnyType); sym = qual.getType().lookup(name); assert(sym.kind != NONE); } else { @@ -1718,7 +1614,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( if (symtype == Type.NoType) return error(tree.pos, "not found: " + decode(name)); else - symtype = checkAccessible(tree.pos, sym, symtype, qual, qualtype); + symtype = infer.checkAccessible(tree.pos, sym, symtype, qual, qualtype); //System.out.println(sym.name + ":" + symtype);//DEBUG if (uninst.length != 0) { symtype match { @@ -2140,7 +2036,8 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( checkNoEscapeParams(vparams1); val tpe1: Tree = transform(tpe, TYPEmode); if ((sym.flags & CASE) != 0 && vparams.length > 0 && templ.getType() == null) - templ.body = desugarize.addCaseElements(templ.body, vparams(0)); + templ.body = desugarize.addCaseElements( + templ.body, vparams(vparams.length - 1)); val templ1: Tree$Template = transformTemplate(templ, sym); checkNoEscape(tree.pos, sym.info()); @@ -2614,11 +2511,11 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( if (enclClassOrConstructorContext == Context.NONE) { fn1 match { case Tree$Select(fn1qual, _) => - fn1.setType(checkAccessible( + fn1.setType(infer.checkAccessible( fn1.pos, constr, fn1.getType(), fn1qual, fn1qual.getType())); case _ => if (constr.owner().isPackageClass()) - fn1.setType(checkAccessible( + fn1.setType(infer.checkAccessible( fn1.pos, constr, fn1.getType(), Tree.Empty, constr.owner().getType())); } } else { @@ -2626,14 +2523,14 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( if (cowner.isConstructor()) // we are in a superclass constructor call fn1.setType( - checkAccessible( + infer.checkAccessible( fn1.pos, constr, fn1.getType(), make.Super(tree.pos, Names.EMPTY.toTypeName(), Names.EMPTY.toTypeName()), cowner.constructorClass().typeConstructor())); else - fn1.setType(checkAccessible( + fn1.setType(infer.checkAccessible( fn1.pos, constr, fn1.getType(), enclClassOrConstructorContext.tree, cowner.typeConstructor())); diff --git a/sources/scala/tools/scalac/typechecker/DeSugarize.scala b/sources/scala/tools/scalac/typechecker/DeSugarize.scala index 10cdfc630b..6f0e93e9a3 100644 --- a/sources/scala/tools/scalac/typechecker/DeSugarize.scala +++ b/sources/scala/tools/scalac/typechecker/DeSugarize.scala @@ -30,6 +30,7 @@ package scala.tools.scalac.typechecker { class DeSugarize(make: TreeFactory, copy: TreeCopier, gen: TreeGen, infer: scala.tools.scalac.typechecker.Infer, global: scalac_Global) { import Kinds._, Modifiers._; + import scalac.ast.TreeList; protected final val freshNameCreator = global.freshNameCreator; @@ -85,14 +86,18 @@ class DeSugarize(make: TreeFactory, copy: TreeCopier, gen: TreeGen, infer: scala */ def FunType(tree: Tree): Tree = tree match { case Tree$FunType(argtpes, restpe) => + mkFunType(tree.pos, argtpes, restpe) + } + + def mkFunType(pos: int, argtpes: Array[Tree], restpe: Tree): Tree = { val types = new Array[Tree](argtpes.length + 1); System.arraycopy(argtpes, 0, types, 0, argtpes.length); types(argtpes.length) = restpe; make.AppliedType( - tree.pos, + pos, make.Select( - tree.pos, - make.Ident(tree.pos, Names.scala), + pos, + make.Ident(pos, Names.scala), Name.fromString("Function" + argtpes.length).toTypeName()), types); } @@ -288,6 +293,50 @@ class DeSugarize(make: TreeFactory, copy: TreeCopier, gen: TreeGen, infer: scala } } + /** expands view-bounded class and method definitions + */ + def Definition(tree: Tree) = + tree match { + case Tree$ClassDef(mods, name, tparams, vparams, tpe, templ) => + make.ClassDef(tree.pos, mods, name, tparams, + addViewParams(tparams, vparams), tpe, templ); + case Tree$DefDef(mods, name, tparams, vparams, tpe, rhs) => + make.DefDef(tree.pos, mods, name, tparams, + addViewParams(tparams, vparams), tpe, rhs) + + case _ => + tree + } + + def addViewParams(tparams: Array[Tree$AbsTypeDef], vparams: Array[Array[Tree$ValDef]]): Array[Array[Tree$ValDef]] = { + var viewparams = new TreeList(); + var i = 0; + while (i < tparams.length) { + tparams(i) match { + case Tree$AbsTypeDef(mods, tname, rhs, _) if (mods & VIEWBOUND) != 0 => + viewparams.append( + make.ValDef( + tparams(i).pos, + PARAM | SYNTHETIC, + Names.view, + mkFunType( + tparams(i).pos, + NewArray.Tree(make.Ident(tparams(i).pos, tname)), + rhs.duplicate()), + Tree.Empty)); + case _ => + } + i = i + 1 + } + if (viewparams.length() > 0) { + val vparams1 = new Array[Array[Tree$ValDef]](vparams.length + 1); + vparams1(0) = new Array[Tree$ValDef](viewparams.length()); + viewparams.copyTo(vparams1(0)); + System.arraycopy(vparams, 0, vparams1, 1, vparams.length); + vparams1 + } else vparams + } + /** expands pattern definitions * in case pattern is a simple (typed) identifier: * val x = e ==> val x = e diff --git a/sources/scala/tools/scalac/typechecker/Infer.scala b/sources/scala/tools/scalac/typechecker/Infer.scala index 54dd1f748f..4dc4c36375 100644 --- a/sources/scala/tools/scalac/typechecker/Infer.scala +++ b/sources/scala/tools/scalac/typechecker/Infer.scala @@ -30,69 +30,13 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal def this(trans: Transformer) = this(trans.global, trans.gen, trans.make); -// View generator, overridable */ +// Context accessor and error function, overridable */ - def getContextViewMeths: List[View] = List(); + def getContext: Context = Context.NONE; - 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 - } - } + def error(pos: int, msg: String): Tree = + throw new Type$Error(msg); - 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()); - if (obj.isExternal() == clazz.isExternal()) { - //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 = if (tp.prefix() == Type.NoType) Tree.Empty - else 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() - } else List() - } // Error messages ------------------------------------------------------------- @@ -228,6 +172,197 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal flip(variance(tparam, tparams)) & variance(tparam, restype) } +// Accessibility ------------------------------------------------------------ + + /** Check that `sym' is accessible as a member of tree `site' in current context. + */ + def checkAccessible(pos: int, sym: Symbol, symtype: Type, site: Tree, sitetype: Type): Type = { + //System.out.println("check acc " + sym);//DEBUG + if ((sym.owner().flags & INCONSTRUCTOR) != 0 && + !(sym.kind == TYPE && sym.isParameter()) && + site.isInstanceOf[Tree$This]) { + error(pos, "" + sym + " cannot be accessed from constructor"); + Type.ErrorType; + } else { + symtype match { + case Type$OverloadedType(alts, alttypes) => + var nacc: int = 0; + var i = 0; while (i < alts.length) { + if (isAccessible(alts(i), site, sitetype)) + nacc = nacc + 1; + i = i + 1 + } + if (nacc == 0) { + error(pos, "" + sym + " cannot be accessed in " + sitetype.widen()); + Type.ErrorType + } else { + val alts1: Array[Symbol] = new Array[Symbol](nacc); + val alttypes1: Array[Type] = new Array[Type](nacc); + nacc = 0; + var i = 0; while (i < alts.length) { + if (isAccessible(alts(i), site, sitetype)) { + alts1(nacc) = alts(i); + alttypes1(nacc) = alttypes(i); + nacc = nacc + 1; + } + i = i + 1 + } + new Type$OverloadedType(alts1, alttypes1) + } + case _ => + if (isAccessible(sym, site, sitetype)) { + symtype + } else { + error(pos, "" + sym + " cannot be accessed in " + sitetype.widen()); + Type.ErrorType + } + } + } + } + + /** Is `sym' accessible as a member of tree `site' in current context? + */ + private def isAccessible(sym: Symbol, site: Tree, sitetype: Type): boolean = { + + /** Are we inside definition of `owner'? + */ + def accessWithin(owner: Symbol): boolean = { + var c: Context = getContext; + while (c != Context.NONE && c.owner != owner) { + c = c.outer.enclClass; + } + c != Context.NONE; + } + + /** Is `clazz' a subclass of an enclosing class? + */ + def isSubClassOfEnclosing(clazz: Symbol): boolean = { + var c: Context = getContext; + while (c != Context.NONE && !clazz.isSubClass(c.owner)) { + c = c.outer.enclClass; + } + c != Context.NONE; + } + + (sym.flags & (PRIVATE | PROTECTED)) == 0 + || + {val owner = if (sym.isConstructor()) sym.constructorClass() + else sym.owner(); + accessWithin(owner) + || + ((sym.flags & PRIVATE) == 0) && + (site.isInstanceOf[Tree$Super] || + (sitetype.symbol().isSubClass(owner) && + isSubClassOfEnclosing(sitetype.symbol()))) + } + } + +// Views --------------------------------------------------------------------- + + 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()); + if (obj.isExternal() == clazz.isExternal()) { + //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 = if (tp.prefix() == Type.NoType) Tree.Empty + else 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() + } else List() + } + + private def getViews(tp: Type): List[View] = { + memberViews(tp) ::: getContext.viewMeths; + } + + def viewExpr(pos: int, v: View): Tree = { + val qual = v.qual.duplicate(); + qual.pos = pos; + val viewType = checkAccessible( + pos, v.sym, v.symtype, qual, qual.getType()); + make.Select(pos, qual, v.sym.name) + .setSymbol(v.sym).setType(viewType) + } + + def viewArg(pos: int, vtype: Type, targs: Array[Type]): Tree = { + val vargs = vtype.typeArgs(); + val v = bestView(vargs(0), vargs(1), Names.EMPTY); + if (v != null) { + var vtree = viewExpr(pos, v); + vtree.getType() match { + case Type$PolyType(vtparams, vrestype) => + assert(vtparams.length != 0); + vtree = exprInstance(vtree, vtparams, vrestype, vtype); + assert(vtree.getType().isSubType(vtype)); + } + vtree + } else { + error(pos, + "type instantiation with [" + + ArrayApply.toString(targs.asInstanceOf[Array[Object]], ",") + + "] failed since " + vargs(0) + " is not viewable as " + vargs(1)); + } + } + + def addViewArgs(tree: Tree, tparams: Array[Symbol], restype: Type, targs: Array[Type]): Tree = { + restype match { + case Type$MethodType(params, _) => + val viewargs = new Array[Tree](params.length); + var i = 0; while (i < params.length) { + viewargs(i) = viewArg( + tree.pos, params(i).getType().subst(tparams, targs), targs); + i = i + 1 + } + gen.Apply(tree, viewargs); + case Type.ErrorType => + tree + } + } + // Type parameter inference ----------------------------------------------------- private class NoInstance(msg: String) extends RuntimeException(msg); @@ -520,7 +655,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal def isCompatible(tp: Type, pt: Type): boolean = isCompatible(tp, pt, true); - def isCompatible(tp: Type, pt: Type, coercible: boolean): boolean = { + def isCompatible(tp: Type, pt: Type, regularValue: boolean): boolean = { def canView(tp: Type): boolean = tp match { case Type$OverloadedType(_, alttypes) => var i = 0; @@ -533,10 +668,11 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal } val tp1 = normalize(tp); if (tp1.isSubType(pt)) true - else if (coercible) { + else if (regularValue) { val argtypes = NewArray.Type(tp1); var viewMeths = getViews(tp1); - while (!viewMeths.isEmpty && !isApplicable(viewMeths.head.symtype, argtypes, pt, false)) + while (!viewMeths.isEmpty && + !isApplicable(viewMeths.head.symtype, argtypes, pt, Names.EMPTY, false)) viewMeths = viewMeths.tail; if (!viewMeths.isEmpty) true // todo: remove @@ -550,9 +686,9 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal def isCompatible(tps: Array[Type], pts: Array[Type]): boolean = isCompatible(tps, pts, true); - def isCompatible(tps: Array[Type], pts: Array[Type], coercible: boolean): boolean = { + def isCompatible(tps: Array[Type], pts: Array[Type], regularValue: boolean): boolean = { var i = 0; while (i < tps.length) { - if (!isCompatible(tps(i), pts(i), coercible)) return false; + if (!isCompatible(tps(i), pts(i), regularValue)) return false; i = i + 1 } true @@ -583,10 +719,10 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal exprTypeArgs(tparams, restype, pt, true); private def exprTypeArgs(tparams: Array[Symbol], restype: Type, - pt: Type, coercible: boolean): Array[Type] = { + pt: Type, regularValue: boolean): Array[Type] = { val tvars: Array[Type] = freshVars(tparams); val insttype: Type = restype.subst(tparams, tvars); - if (isCompatible(insttype, pt, coercible)) { + if (isCompatible(insttype, pt, regularValue)) { try { val restype1 = normalize(restype); { var i = 0; while (i < tvars.length) { @@ -647,7 +783,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal private def methTypeArgs(tparams: Array[Symbol], params: Array[Symbol], argtypes: Array[Type], restp: Type, pt: Type, - needToSucceed: boolean, coercible: boolean): Array[Type] = { + needToSucceed: boolean, regularValue: 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); @@ -660,7 +796,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, coercible)) { + if (!isCompatible(restp.subst(tparams, tvars), pt, regularValue)) { if (needToSucceed) throw new NoInstance("result type " + restp + " is incompatible with expected type " + pt); @@ -677,7 +813,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal while (i < argtypes.length) { if (!isCompatible(argtypes(i).widen().subst(tparams, tvars), formals(i).subst(tparams, tvars), - coercible)) { + regularValue)) { if (needToSucceed) { if (global.explaintypes) { Type.explainSwitch = true; @@ -726,14 +862,18 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal } if (0 < i) { val argtrees: Array[Tree] = new Array[Tree](i); + var viewbounded = false; { var j = 0; while (j < i) { argtrees(j) = gen.mkType(tree.pos, targs(j)); + viewbounded = viewbounded | ((tparams(j).flags & VIEWBOUND) != 0); j = j + 1 }} - tree1 = make.TypeApply(tree.pos, tree1, argtrees); + tree1 = make.TypeApply(tree.pos, tree1, argtrees) + .setType(restype.subst(tparams, targs)); + if (viewbounded) + tree1 = addViewArgs(tree1, tparams, restype, targs); } - //System.out.println(Sourcefile.files[Position.file(tree1.pos)] + ": "); - tree1.setType(restype.subst(tparams, targs)) + tree1 } /** Return the instantiated and normalized type of polymorphic expression @@ -877,26 +1017,29 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal * does its result conform to `pt'? */ def isApplicable(ftpe: Type, argtypes: Array[Type], pt: Type): boolean = - isApplicable(ftpe, argtypes, pt, true); + isApplicable(ftpe, argtypes, pt, Names.EMPTY, true); def isApplicable(ftpe: Type, argtypes: Array[Type], pt: Type, - coercible: boolean): boolean = ftpe match { + fieldName: Name, regularValue: 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) && - isCompatible(restpe, pt, coercible); + isCompatible(argtypes, formals, regularValue) && + isCompatible(restpe, pt, regularValue) && + (fieldName == Names.EMPTY || restpe.lookup(fieldName).kind != NONE) case Type$PolyType(tparams, Type$MethodType(params, restpe)) => try { val targs: Array[Type] = methTypeArgs( - tparams, params, argtypes, restpe, pt, false, coercible); + tparams, params, argtypes, restpe, pt, false, regularValue); if (targs != null) { val uninstantiated: Array[Symbol] = normalizeArgs(targs, tparams); isWithinBounds(tparams, targs) && exprTypeArgs(uninstantiated, restpe.subst(tparams, targs), pt, - coercible) != null; + regularValue) != null && + (fieldName == Names.EMPTY || + restpe.subst(tparams, targs).lookup(fieldName).kind != NONE) } else { false } @@ -904,36 +1047,19 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal case ex: NoInstance => false } case _ => - false + if (!regularValue) { + val ftpe1 = applyType(ftpe); + ftpe1 != ftpe && + isApplicable(ftpe1, argtypes, pt, fieldName, false); + } else 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, Type.AnyType, false, coercible); - if (targs != null) { - val uninstantiated: Array[Symbol] = normalizeArgs(targs, tparams); - isWithinBounds(tparams, targs) && - restpe.subst(tparams, targs).lookup(name) != NONE; - } else { - false - } - } catch { - case ex: NoInstance => false - } - case _ => - false - } + def applyType(tp: Type) = + if (tp.isObjectType()) { + val applyMeth: Symbol = tp.lookup(Names.apply); + if (applyMeth != Symbol.NONE) tp.memberType(applyMeth) + else tp + } else tp; /** Does type `ftpe1' specialize type `ftpe2' * when both are alternatives in an overloaded function? @@ -947,6 +1073,9 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal false } + def specializesView(ftpe1: Type, ftpe2: Type): boolean = + specializes(applyType(ftpe1), applyType(ftpe2)); + /** Assign `tree' the type of the alternative which matches * prototype `pt', if it exists. * If several alternatives match `pt', take unique parameterless one. @@ -1070,13 +1199,13 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal /** return view which best matches argument type `tp' and has `name' as member. */ - def bestView(tp: Type, name: Name): View = { + def bestView(tp: Type, pt: 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))) + if (isApplicable(viewMeths.head.symtype, argtypes, pt, name, false) && + (best == null || specializesView(viewMeths.head.symtype, best.symtype))) best = viewMeths.head; viewMeths = viewMeths.tail } @@ -1084,44 +1213,19 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal 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))) + isApplicable(viewMeths.head.symtype, argtypes, pt, name, false) && + !(specializesView(best.symtype, viewMeths.head.symtype) && + !specializesView(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 bestView(tp: Type, pt: Type): View = { - var best: View = null; - var viewMeths = getViews(tp); - val argtypes = NewArray.Type(tp); - 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) { - 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 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.widen() + " to expected type " + pt); + "both " + viewMeths.head.sym + ": " + + viewMeths.head.symtype + viewMeths.head.sym.locationString() + "\n" + + "and " + best.sym + ": " + best.symtype + best.sym.locationString() + + (if (name == Names.EMPTY) + "\nmap argument type " + tp.widen() + " to expected type " + pt + else + "\nadd member `" + name + "' to argument type " + tp.widen())) + } viewMeths = viewMeths.tail; } } diff --git a/test/files/pos/testcast.scala b/test/files/pos/testcast.scala index 6482ed0a6d..15aa01ba72 100644 --- a/test/files/pos/testcast.scala +++ b/test/files/pos/testcast.scala @@ -2,22 +2,25 @@ package test; class A; -class B { +class B extends A { def foo: int = 1; } +object B { + def view(x: B): B1 = null; +} + class B1 { def bar: int = 1 } object C { - def view(x: B): B1 = null; + def view(x: A): B1 = null; } object Test { import C.view; val b: B = null; - System.out.println(C.view(b).bar); System.out.println(b.bar); } |