summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2004-04-01 14:22:48 +0000
committerMartin Odersky <odersky@gmail.com>2004-04-01 14:22:48 +0000
commitbce606fb00b2ab5af4a5913cd7d1c72116bd8566 (patch)
tree7c60a4746a6090b95b127722a0af0ef7bdbdaffa
parent6e1747c335587f75470d10d8ed21e0060c6e436f (diff)
downloadscala-bce606fb00b2ab5af4a5913cd7d1c72116bd8566.tar.gz
scala-bce606fb00b2ab5af4a5913cd7d1c72116bd8566.tar.bz2
scala-bce606fb00b2ab5af4a5913cd7d1c72116bd8566.zip
*** empty log message ***
-rw-r--r--sources/scala/tools/scalac/typechecker/Analyzer.scala153
-rw-r--r--sources/scala/tools/scalac/typechecker/DeSugarize.scala55
-rw-r--r--sources/scala/tools/scalac/typechecker/Infer.scala396
-rw-r--r--test/files/pos/testcast.scala9
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);
}