From 35f72d0a599e3aca2940e295052c0275c0a32533 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 6 Apr 2004 17:57:30 +0000 Subject: *** empty log message *** --- doc/reference/ReferencePart.tex | 7 +- doc/reference/ReferencePartAppendix.tex | 4 +- sources/scala/tools/scalac/ast/parser/Parser.scala | 16 +-- .../tools/scalac/ast/printer/TextTreePrinter.scala | 12 +- .../scala/tools/scalac/typechecker/Analyzer.scala | 63 +++++---- .../tools/scalac/typechecker/DeSugarize.scala | 7 +- sources/scala/tools/scalac/typechecker/Infer.scala | 151 +++++++++++++++------ sources/scalac/ast/TreeGen.java | 2 +- sources/scalac/symtab/ClosureHistory.java | 2 + sources/scalac/symtab/Symbol.java | 31 +++++ sources/scalac/symtab/Type.java | 63 +++++++-- sources/scalac/symtab/classfile/Pickle.java | 14 +- sources/scalac/symtab/classfile/UnPickle.java | 7 +- sources/scalac/typechecker/RefCheck.java | 39 ++++-- test/files/pos/exceptions.scala | 1 - 15 files changed, 305 insertions(+), 114 deletions(-) diff --git a/doc/reference/ReferencePart.tex b/doc/reference/ReferencePart.tex index 9bb914f8bb..f0bb1842a7 100644 --- a/doc/reference/ReferencePart.tex +++ b/doc/reference/ReferencePart.tex @@ -42,8 +42,8 @@ These sets are extended in the usual way to Unicode. \syntax\begin{lstlisting} op ::= special {special} -varid ::= lower {letter $|$ digit} [`_' [id]] -id ::= upper {letter $|$ digit} [`_' [id]] +varid ::= lower {letter $|$ digit} [`_' {digit} [id]] +id ::= upper {letter $|$ digit} [`_' {digit} [id]] | varid | op | ```string chars`'' @@ -2206,13 +2206,14 @@ A class definition which starts with the reserved word \code{trait} instead of \code{class} defines a trait. A trait is a specific instance of an abstract class, so the \code{abstract} modifier is redundant for it. The template of a trait must satisfy the following -three restrictions. +four restrictions. \begin{enumerate} \item All base classes of the trait are traits. \item All parent class constructors of a template must be primary constructors with empty value parameter lists. \item All non-empty statements in the template are either imports or pure definitions. +\item A trait may not have secondary constructors. \end{enumerate} A {\em pure} definition can be evaluated without any side effect. Function, type, class, or object definitions are always pure. A value diff --git a/doc/reference/ReferencePartAppendix.tex b/doc/reference/ReferencePartAppendix.tex index 2d1f48eb9e..085972f590 100644 --- a/doc/reference/ReferencePartAppendix.tex +++ b/doc/reference/ReferencePartAppendix.tex @@ -12,8 +12,8 @@ form. special ::= $\mbox{\rm\em ``all other characters except parentheses ([{}]) and periods''}$ op ::= special {special} - varid ::= lower {letter | digit} [`_' [id]] - id ::= upper {letter | digit} [`_' [id]] + varid ::= lower {letter | digit} [`_' {digit} [id]] + id ::= upper {letter | digit} [`_' {digit} [id]] | varid | op | `\'stringLit diff --git a/sources/scala/tools/scalac/ast/parser/Parser.scala b/sources/scala/tools/scalac/ast/parser/Parser.scala index 59d9a2821e..c33e62a76e 100644 --- a/sources/scala/tools/scalac/ast/parser/Parser.scala +++ b/sources/scala/tools/scalac/ast/parser/Parser.scala @@ -1849,15 +1849,15 @@ class Parser(unit: Unit) { /** ClassDef ::= Id [TypeParamClause] [ParamClause] [`:' SimpleType] ClassTemplate */ def classDef(mods: int): Array[Tree] = { - val lhs = new ListBuffer[Tuple4[Int, Name, Array[Tree$AbsTypeDef], Array[Array[Tree$ValDef]]]]; - do { - s.nextToken(); - lhs.append(Tuple4(s.pos, - ident().toTypeName(), - typeParamClauseOpt(true), - paramClauseOpt())); + val lhs = new ListBuffer[Tuple4[Int, Name, Array[Tree$AbsTypeDef], Array[Array[Tree$ValDef]]]]; + do { + s.nextToken(); + lhs.append(Tuple4(s.pos, + ident().toTypeName(), + typeParamClauseOpt(true), + paramClauseOpt())); } while (s.token == COMMA); - val thistpe = simpleTypedOpt(); + val thistpe = simpleTypedOpt(); val template = classTemplate(); val ts = new myTreeList(); lhs foreach { case Tuple4(p, n, tp, vp) => diff --git a/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala b/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala index 35f0d1a4be..14da5e6613 100644 --- a/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala +++ b/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala @@ -166,6 +166,7 @@ class TextTreePrinter(writer: PrintWriter) with TreePrinter { protected final val TXT_EQUAL = Simple("="); protected final val TXT_SUPERTYPE = Simple(">:"); protected final val TXT_SUBTYPE = Simple("<:"); + protected final val TXT_VIEWBOUND = Simple("<+"); protected final val TXT_HASH = Simple("#"); protected final val TXT_RIGHT_ARROW = Simple("=>"); protected final val TXT_LEFT_PAREN = Simple("("); @@ -293,7 +294,7 @@ class TextTreePrinter(writer: PrintWriter) with TreePrinter { print(KW_TYPE); print(Space); printSymbolDefinition(tree.symbol(), name); - printBounds(lobound, rhs); + printBounds(lobound, rhs, mods); case Tree$AliasTypeDef(mods, name, tparams, rhs) => printModifiers(mods); @@ -697,7 +698,7 @@ class TextTreePrinter(writer: PrintWriter) with TreePrinter { case Tree$AbsTypeDef(mods, name, bound, lobound) => printModifiers(mods); printSymbolDefinition(tree.symbol(), name); - printBounds(lobound, bound); + printBounds(lobound, bound, mods); case Tree$ValDef(mods, name, tpe, Tree.Empty) => printModifiers(mods); @@ -708,7 +709,7 @@ class TextTreePrinter(writer: PrintWriter) with TreePrinter { Debug.abort("bad parameter: " + tree); } - protected def printBounds(lobound: Tree, hibound: Tree): unit = { + protected def printBounds(lobound: Tree, hibound: Tree, mods: int): unit = { val definitions: Definitions = scalac_Global.instance.definitions; val printLoBound: Boolean = if (lobound.getType() != null) @@ -721,7 +722,10 @@ class TextTreePrinter(writer: PrintWriter) with TreePrinter { hibound.getType().symbol() != definitions.ANY_CLASS else !"scala.Any".equals(hibound.toString()); - if (printHiBound) printOpt(TXT_SUBTYPE, hibound, true); + if (printHiBound) + printOpt( + if ((mods & Modifiers.VIEWBOUND) != 0) TXT_VIEWBOUND else TXT_SUBTYPE, + hibound, true); } } } diff --git a/sources/scala/tools/scalac/typechecker/Analyzer.scala b/sources/scala/tools/scalac/typechecker/Analyzer.scala index 569b435f32..18cae3fe6d 100644 --- a/sources/scala/tools/scalac/typechecker/Analyzer.scala +++ b/sources/scala/tools/scalac/typechecker/Analyzer.scala @@ -408,9 +408,12 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( //System.out.println("checking " + sym);//DEBUG checkNonCyclic( pos, pre.memberInfo(sym).subst(sym.typeParams(), args)); - if (sym.kind == TYPE) + if (sym.kind == TYPE) { checkNonCyclic( pos, pre.memberLoBound(sym).subst(sym.typeParams(), args)); + checkNonCyclic( + pos, pre.memberVuBound(sym).subst(sym.typeParams(), args)); + } sym.flags = sym.flags & ~LOCKED; } @@ -567,10 +570,21 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( // Views ----------------------------------------------------------------------- - 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); + private def applyView(v: View, tree: Tree, mode: int, pt: Type): Tree = { + val vexpr = infer.viewExpr(tree.pos, v); + val vapp = transform( + make.Apply(tree.pos, vexpr, NewArray.Tree(tree)), mode, pt); + if (v.symtype.isObjectType()) { + gen.If( + gen.Apply( + gen.Select( + vexpr.duplicate(), + definitions.ANY_EQEQ), + NewArray.Tree(gen.mkNullLit(tree.pos))), + gen.mkNullLit(tree.pos), + vapp) + } else vapp + } // Contexts ------------------------------------------------------------------- @@ -1156,7 +1170,12 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( tree.asInstanceOf[Tree$AbsTypeDef].rhs = rhs; lobound = transform(lobound, TYPEmode); (tree.asInstanceOf[Tree$AbsTypeDef]).lobound = lobound; - owntype = rhs.getType(); + if (sym.isViewBounded()) { + sym.setVuBound(rhs.getType()); + owntype = definitions.ANY_TYPE(); + } else { + owntype = rhs.getType(); + } sym.setLoBound(lobound.getType()); owntype.symbol().initialize();//to detect cycles todo: needed? @@ -1917,7 +1936,8 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( System.arraycopy(tparams, 0, tparams2, 0, tparams.length); System.arraycopy(tparams1, 0, tparams2, tparams.length, tparams1.length); } - transformArgs(pos, meth, tparams2, restp, argMode, args, pt) + transformArgs(pos, meth, tparams2, + infer.skipViewParams(tparams2, restp), argMode, args, pt) case Type.ErrorType => var i = 0; while (i < args.length) { @@ -2425,28 +2445,13 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( // match against arguments fn1.getType() match { case Type$PolyType(tparams, restp) if (tparams.length == argtypes.length) => - /* constant fold asInstanceOf calls. - fn1 match { - case Tree$Select(qual, name) => - if (fn1.symbol() == definitions.ANY_AS && - qual.getType().isInstanceOf[Type$ConstantType]) { - val restp1: Type = constfold.foldAsInstanceOf( - tree.pos, - qual.getType().asInstanceOf[Type$ConstantType], - argtypes(0)); - restp1 match { - case ConstantType(_, Object value) => - return make.Literal(tree.pos, value) - .setType(restp1); - case => - } - } - case _ => - } - */ constfold.tryToFold( - copy.TypeApply(tree, fn1, args1) - .setType(restp.subst(tparams, argtypes))); + infer.completeTypeApply( + copy.TypeApply(tree, fn1, args1) + .setType(restp.subst(tparams, argtypes)))); + + case Type.ErrorType => + tree.setType(Type.ErrorType) case fn1tp => if (!fn1tp.isError()) error(tree.pos, @@ -2531,7 +2536,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( if (tsym == c) { fn0 match { case Tree$AppliedType(_, targs) => - fn1 = gen.TypeApply(fn1, targs); + fn1 = infer.completeTypeApply(gen.TypeApply(fn1, targs)); case _ => } } else { diff --git a/sources/scala/tools/scalac/typechecker/DeSugarize.scala b/sources/scala/tools/scalac/typechecker/DeSugarize.scala index d4a5c84297..59ec8946d6 100644 --- a/sources/scala/tools/scalac/typechecker/DeSugarize.scala +++ b/sources/scala/tools/scalac/typechecker/DeSugarize.scala @@ -293,17 +293,19 @@ class DeSugarize(make: TreeFactory, copy: TreeCopier, gen: TreeGen, infer: scala /** expands view-bounded class and method definitions */ - def Definition(tree: Tree) = + def Definition(tree: Tree): Tree = tree match { case Tree$ClassDef(mods, name, tparams, vparams, tpe, templ) => + //System.out.println("DEF " + make.ClassDef(tree.pos, mods, name, tparams, addViewParams(tparams, vparams), tpe, templ));//DEBUG 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 + return tree } def addViewParams(tparams: Array[Tree$AbsTypeDef], vparams: Array[Array[Tree$ValDef]]): Array[Array[Tree$ValDef]] = { @@ -330,6 +332,7 @@ class DeSugarize(make: TreeFactory, copy: TreeCopier, gen: TreeGen, infer: scala val vparams1 = new Array[Array[Tree$ValDef]](vparams.length + 1); vparams1(0) = new Array[Tree$ValDef](viewparams.length()); viewparams.copyTo(vparams1(0)); + //for (val t <- vparams1(0)) System.out.println("new view param: " + t);//DEBUG System.arraycopy(vparams, 0, vparams1, 1, vparams.length); vparams1 } else vparams diff --git a/sources/scala/tools/scalac/typechecker/Infer.scala b/sources/scala/tools/scalac/typechecker/Infer.scala index ab69716ad2..8dada48e1b 100644 --- a/sources/scala/tools/scalac/typechecker/Infer.scala +++ b/sources/scala/tools/scalac/typechecker/Infer.scala @@ -115,7 +115,9 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal case VAL => variance(tparam, sym.info()) case TYPE => - variance(tparam, sym.info()) & flip(variance(tparam, sym.loBound())) + variance(tparam, sym.info()) & + flip(variance(tparam, sym.loBound())) & + variance(tparam, sym.vuBound()) case ALIAS => cut(variance(tparam, sym.info())) case _ => @@ -151,7 +153,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal v } - /** Does given `tparam' occur with variance `v' in type? + /** Compute variance of type parameter `tparam' in type `tp'. */ private def variance(tparam: Symbol, tp: Type): int = tp match { case Type.ErrorType | Type.AnyType | Type.NoType | Type.NoPrefix | @@ -318,36 +320,62 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal } 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) + pos, v.sym, v.symtype, v.qual, v.qual.getType()); + v.qual match { + case Tree.Empty => + make.Ident(pos, v.sym.name) + .setSymbol(v.sym).setType(viewType) + case _ => + val qual = v.qual.duplicate(); + qual.pos = pos; + make.Select(pos, qual, v.sym.name) + .setSymbol(v.sym).setType(viewType) + } + } + + private def viewObj(meth: Tree, msym: Symbol) = msym.getType() match { + case Type$MethodType(params: Array[Symbol], _) => + assert(params.length == 1); + val paramsym = params(0).cloneSymbol(getContext.owner); + gen.mkFunction( + meth.pos, + NewArray.ValDef(gen.mkParam(paramsym)), + gen.Apply(meth, NewArray.Tree(gen.Ident(meth.pos, paramsym))), + meth.getType().resultType(), + getContext.owner) + case _ => + meth } - def viewArg(pos: int, vtype: Type, targs: Array[Type]): Tree = { + private 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 + if (vargs(0).isSubType(vargs(1))) { + gen.mkNullLit(pos) } else { - error(pos, - "type instantiation with [" + - ArrayApply.toString(targs.asInstanceOf[Array[Object]], ",") + - "] failed since " + vargs(0) + " is not viewable as " + vargs(1)); - gen.mkDefaultValue(pos, vtype) + val v = bestView(vargs(0), vargs(1), Names.EMPTY); + if (v != null) { + var vmeth = viewExpr(pos, v); + vmeth.getType() match { + case Type$PolyType(vtparams, vrestype) => + assert(vtparams.length != 0); + vmeth = exprInstance(vmeth, vtparams, vrestype, vtype); + assert(vmeth.getType().isSubType(vtype)); + case _ => + } + viewObj(vmeth, v.sym) + } else { + error(pos, + "type instantiation with [" + + ArrayApply.toString(targs.asInstanceOf[Array[Object]], ",") + + "] failed since " + vargs(0) + " is not viewable as " + vargs(1)); + gen.mkDefaultValue(pos, vtype) + } } } - def addViewArgs(tree: Tree, tparams: Array[Symbol], restype: Type, targs: Array[Type]): Tree = { + private def passViewArgs(tree: Tree, tparams: Array[Symbol], restype: Type, + targs: Array[Type]): Tree = restype match { case Type$MethodType(params, _) => val viewargs = new Array[Tree](params.length); @@ -356,10 +384,42 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal tree.pos, params(i).getType().subst(tparams, targs), targs); i = i + 1 } + //System.out.println("new view args: " + gen.Apply(tree, viewargs));//DEBUG gen.Apply(tree, viewargs); case Type.ErrorType => tree } + + def isViewBounded(tparams: Array[Symbol]) = { + var viewbounded = false; + var j = 0; while (j < tparams.length) { + viewbounded = viewbounded | tparams(j).isViewBounded(); + j = j + 1 + } + viewbounded + } + + def skipViewParams(tparams: Array[Symbol], tp: Type): Type = tp match { + case Type$MethodType(_, restp) if isViewBounded(tparams) => + restp + case _ => + tp + } + + def completeTypeApply(tree: Tree): Tree = { + tree match { + case Tree$TypeApply(fn, targs) => + fn.getType() match { + case Type$PolyType(tparams, restp) if tparams.length == targs.length => + if (isViewBounded(tparams)) { + val result = passViewArgs(tree, tparams, restp, Tree.typeOf(targs)); + //System.out.println("completed type apply: " + result + ":" + result.getType());//DEBUG + result + } else tree + case _ => tree + } + case _ => tree + } } // Type parameter inference ----------------------------------------------------- @@ -621,6 +681,10 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal newparams(i).loBound() .subst(tparams, newparams) .subst(tparams1, newparams1)); + newparams(i).setVuBound( + newparams(i).vuBound() + .subst(tparams, newparams) + .subst(tparams1, newparams1)); i = i + 1 }} new Type$PolyType(newparams, restp1.subst(tparams, newparams)) @@ -693,14 +757,18 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal true } - /** Type arguments mapped to `scala.All' are taken to be uninstantiated. + /** Type arguments mapped to `scala.All' and not covariant in `restype' + * are taken to be uninstantiated. * Map all those type arguments to their corresponding type parameters * and return all these type parameters as result. */ - private def normalizeArgs(targs: Array[Type], tparams: Array[Symbol]): Array[Symbol] = { + private def normalizeArgs(targs: Array[Type], tparams: Array[Symbol], restype: Type): Array[Symbol] = { var uninstantiated: Type$List = Type$List.EMPTY; { var i = 0; while (i < targs.length) { - if (targs(i).symbol() == definitions.ALL_CLASS) { + if (targs(i).symbol() == definitions.ALL_CLASS && + (variance(tparams(i), restype) & COVARIANT) == 0 && + !tparams(i).isViewBounded()) { + //System.out.println("normalizing " + tparams(i) + " / " + restype);//DEBUG targs(i) = tparams(i).getType(); uninstantiated = Type$List.append(uninstantiated, targs(i)); } @@ -783,7 +851,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal argtypes: Array[Type], restp: Type, pt: 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 + //System.out.println("methTypeArgs, tparams = " + ArrayApply.toString(tparams.asInstanceOf[Array[Object]]) + ", params = " + ArrayApply.toString(params.asInstanceOf[Array[Object]]) + ", type(params) = " + ArrayApply.toString(Symbol.getType(params).asInstanceOf[Array[Object]]) + ", argtypes = " + ArrayApply.toString(argtypes.asInstanceOf[Array[Object]]) + ", restp = " + restp + ", pt = " + pt);//DEBUG val tvars: Array[Type] = freshVars(tparams); val formals: Array[Type] = formalTypes(params, argtypes.length); @@ -834,7 +902,6 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal solve(tparams, false, variance(tparams, formals), tvars, i); i = i + 1 }} - //System.out.println(" = " + ArrayApply.toString(tvars));//DEBUG tvars } @@ -861,18 +928,16 @@ 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) - .setType(restype.subst(tparams, targs)); - if (viewbounded) - tree1 = addViewArgs(tree1, tparams, restype, targs); + completeTypeApply( + make.TypeApply(tree.pos, tree1, argtrees) + .setType(restype.subst(tparams, targs))) + } else { + tree1.setType(restype.subst(tparams, targs)); } - tree1 } /** Return the instantiated and normalized type of polymorphic expression @@ -934,6 +999,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal * types `argtypes' and its result type is compatible with `pt'. */ def methodInstance(tree: Tree, tparams: Array[Symbol], restype: Type, argtypes: Array[Type], pt: Type): Tree = { + //System.out.println("methodinstance, tree = " + tree + ":" + tree.getType() + ", tparams = " + ArrayApply.toString(tparams.asInstanceOf[Array[Object]]) + ", restype = " + restype + ", argtypes = " + ArrayApply.toString(argtypes.asInstanceOf[Array[Object]]) + ", pt = " + pt);//DEBUG restype match { case Type$PolyType(tparams1, restype1) => val tparams2: Array[Symbol] = new Array[Symbol](tparams.length + tparams1.length); @@ -944,7 +1010,14 @@ 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, false); + restpe match { + case Type$MethodType(params1, restpe1) if isViewBounded(tparams) => + targs = methTypeArgs( + tparams, params1, argtypes, restpe1, pt, true, false); + case _ => + targs = methTypeArgs( + tparams, params, argtypes, restpe, pt, true, false); + } } catch { case ex: NoInstance => throw new Type$Error( @@ -954,7 +1027,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal Type.widen(argtypes), Type.AnyType) + "\n --- because ---\n" + ex.getMessage()); } - val uninstantiated: Array[Symbol] = normalizeArgs(targs, tparams); + val uninstantiated: Array[Symbol] = normalizeArgs(targs, tparams, restype); checkBounds(tparams, targs, "inferred "); val restype1: Type = if (uninstantiated.length == 0) restype @@ -1032,7 +1105,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal val targs: Array[Type] = methTypeArgs( tparams, params, argtypes, restpe, pt, false, regularValue); if (targs != null) { - val uninstantiated: Array[Symbol] = normalizeArgs(targs, tparams); + val uninstantiated: Array[Symbol] = normalizeArgs(targs, tparams, restpe); isWithinBounds(tparams, targs) && exprTypeArgs(uninstantiated, restpe.subst(tparams, targs), pt, diff --git a/sources/scalac/ast/TreeGen.java b/sources/scalac/ast/TreeGen.java index 1bbb32aebf..4abd940f9c 100644 --- a/sources/scalac/ast/TreeGen.java +++ b/sources/scalac/ast/TreeGen.java @@ -1094,7 +1094,7 @@ public class TreeGen implements Kinds, Modifiers, TypeTags { AbsTypeDef tree = make.AbsTypeDef( sym.pos, sym, - TypeTerm(sym.pos, sym.nextInfo()), + TypeTerm(sym.pos, sym.isViewBounded() ? sym.vuBound() : sym.nextInfo()), TypeTerm(sym.pos, sym.loBound())); tree.setType(Type.NoType); return tree; diff --git a/sources/scalac/symtab/ClosureHistory.java b/sources/scalac/symtab/ClosureHistory.java index 8825fb3e20..c17ad46f90 100644 --- a/sources/scalac/symtab/ClosureHistory.java +++ b/sources/scalac/symtab/ClosureHistory.java @@ -14,6 +14,7 @@ import java.util.TreeMap; import scalac.Global; import scalac.framework.History; import scalac.util.Debug; +import scalac.util.ArrayApply; /** This class implements a closure history. */ public class ClosureHistory extends History { @@ -43,6 +44,7 @@ public class ClosureHistory extends History { closure[0] = clasz.type(); for (int i = 1; i < closure.length; i++) closure[i] = (Type)types.next(); + //System.out.println("closure(" + owner + ") = " + ArrayApply.toString(closure));//DEBUG return closure; } diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java index c65bdcdc6c..ccd9f2632a 100644 --- a/sources/scalac/symtab/Symbol.java +++ b/sources/scalac/symtab/Symbol.java @@ -504,6 +504,12 @@ public abstract class Symbol implements Modifiers, Kinds { throw new ApplicationError("setLoBound inapplicable for " + this); } + /** Set the view bound of this type variable + */ + public Symbol setVuBound(Type lobound) { + throw new ApplicationError("setVuBound inapplicable for " + this); + } + /** Add an auxiliary constructor to class. */ public void addConstructor(Symbol constr) { @@ -575,6 +581,13 @@ public abstract class Symbol implements Modifiers, Kinds { return kind == VAL && (flags & MUTABLE) != 0; } + /** Does this symbol denote a view bounded type variable? */ + public final boolean isViewBounded() { + Global global = Global.instance; + return kind == TYPE && (flags & VIEWBOUND) != 0 && + global.currentPhase.id <= global.PHASE.REFCHECK.id(); + } + /** * Does this symbol denote a final method? A final method is one * that can't be overridden in a subclass. This method assumes @@ -1278,6 +1291,12 @@ public abstract class Symbol implements Modifiers, Kinds { return Global.instance.definitions.ALL_TYPE(); } + /** The view bound of this type variable + */ + public Type vuBound() { + return Global.instance.definitions.ANY_TYPE(); + } + /** Get this.type corresponding to this symbol */ public Type thisType() { @@ -1757,6 +1776,7 @@ final class AliasTypeSymbol extends TypeSymbol { final class AbsTypeSymbol extends TypeSymbol { private Type lobound = null; + private Type vubound = null; /** Initializes this instance. */ AbsTypeSymbol(int pos, Name name, Symbol owner, int flags, int attrs) { @@ -1769,14 +1789,25 @@ final class AbsTypeSymbol extends TypeSymbol { return lobound == null ? Global.instance.definitions.ALL_TYPE() : lobound; } + public Type vuBound() { + initialize(); + return vubound == null ? Global.instance.definitions.ANY_TYPE() : vubound; + } + public Symbol setLoBound(Type lobound) { this.lobound = lobound; return this; } + public Symbol setVuBound(Type vubound) { + this.vubound = vubound; + return this; + } + protected TypeSymbol cloneTypeSymbolImpl(Symbol owner, int attrs) { TypeSymbol clone = new AbsTypeSymbol(pos, name, owner, flags, attrs); clone.setLoBound(loBound()); + clone.setVuBound(vuBound()); return clone; } diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java index 9adcade4a2..4bff125e53 100644 --- a/sources/scalac/symtab/Type.java +++ b/sources/scalac/symtab/Type.java @@ -1035,8 +1035,10 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { } for (int i = 0; i < syms2.length; i++) { syms2[i].setInfo(syms1[i].info().subst(syms1, syms2)); - if (syms2[i].kind == TYPE) + if (syms2[i].kind == TYPE) { syms2[i].setLoBound(syms1[i].loBound().subst(syms1, syms2)); + syms2[i].setVuBound(syms1[i].vuBound().subst(syms1, syms2)); + } } for (int i = 0; i < syms2.length; i++) { members2.enter(syms2[i]); @@ -1086,6 +1088,12 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { if (!dontClone) sym = sym.cloneSymbol(); sym.setLoBound(lb1); } + Type vb = sym.vuBound(); + Type vb1 = apply(vb); + if (vb != vb1) { + if (!dontClone) sym = sym.cloneSymbol(); + sym.setVuBound(vb1); + } } return sym; } @@ -1319,6 +1327,12 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { return sym.loBound().asSeenFrom(this, sym.owner()); } + /** The view bound of `sym', seen as a member of this type. + */ + public Type memberVuBound(Symbol sym) { + return sym.vuBound().asSeenFrom(this, sym.owner()); + } + // Substitutions --------------------------------------------------------------- /** A common map superclass for symbol/symbol and type/symbol substitutions. @@ -1920,7 +1934,8 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { if (ps.length != ps1.length) return false; for (int i = 0; i < ps.length; i++) if (!ps1[i].info().subst(ps1, ps).isSameAs(ps[i].info()) || - !ps[i].loBound().isSameAs(ps1[i].loBound().subst(ps1, ps))) + !ps[i].loBound().isSameAs(ps1[i].loBound().subst(ps1, ps)) || + !ps[i].vuBound().isSameAs(ps1[i].vuBound().subst(ps1, ps))) return false; return res.isSubType(res1.subst(ps1, ps)); } @@ -1979,9 +1994,9 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { return true; } - case TypeRef(_, Symbol sym, Type[] args): + case TypeRef(_, Symbol sym, _): switch (that) { - case TypeRef(Type pre1, Symbol sym1, _): + case TypeRef(_, Symbol sym1, _): if (sym1.kind == TYPE && this.isSubType(that.loBound())) return true; } @@ -2092,7 +2107,9 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { self.memberInfo(sym).subst(tparams, targs) .isSubType(sym1.info().substThis(sym1.owner(), self)) && sym1.loBound().substThis(sym1.owner(), self) - .isSubType(self.memberLoBound(sym).subst(tparams, targs)) + .isSubType(self.memberLoBound(sym).subst(tparams, targs)) && + self.memberVuBound(sym).subst(tparams, targs) + .isSubType(sym1.vuBound().substThis(sym1.owner(), self)) || (sym.kind == TYPE && sym1.kind == ALIAS && sym1.info().unalias().isSameAs(sym.type()))); @@ -2203,7 +2220,8 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { if (ps.length != ps1.length) return false; for (int i = 0; i < ps.length; i++) if (!ps1[i].info().subst(ps1, ps).isSameAs(ps[i].info()) || - !ps1[i].loBound().subst(ps1, ps).isSameAs(ps[i].loBound())) + !ps1[i].loBound().subst(ps1, ps).isSameAs(ps[i].loBound()) || + !ps1[i].vuBound().subst(ps1, ps).isSameAs(ps[i].vuBound())) return false; return res.isSameAs(res1.subst(ps1, ps)); } @@ -2293,6 +2311,9 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { sym2.owner(), sym1.owner().thisType())) || !sym1.loBound().isSameAs( sym2.loBound().substThis( + sym2.owner(), sym1.owner().thisType())) || + !sym1.vuBound().isSameAs( + sym2.vuBound().substThis( sym2.owner(), sym1.owner().thisType()))) return false; } @@ -2656,6 +2677,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { private static Type polyLub(Type[] tps, Symbol[] tparams0) { Type[][] hiboundss = new Type[tparams0.length][tps.length]; Type[][] loboundss = new Type[tparams0.length][tps.length]; + Type[][] vuboundss = new Type[tparams0.length][tps.length]; Type[] restps = new Type[tps.length]; for (int i = 0; i < tps.length; i++) { switch (tps[i]) { @@ -2666,6 +2688,8 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { .subst(tparams, tparams0); loboundss[j][i] = tparams[j].loBound() .subst(tparams, tparams0); + vuboundss[j][i] = tparams[j].vuBound() + .subst(tparams, tparams0); } restps[i] = restp.subst(tparams, tparams0); } else { @@ -2678,15 +2702,18 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { } Type[] hibounds = new Type[tparams0.length]; Type[] lobounds = new Type[tparams0.length]; + Type[] vubounds = new Type[tparams0.length]; for (int j = 0; j < tparams0.length; j++) { hibounds[j] = glb(hiboundss[j]); lobounds[j] = lub(loboundss[j]); + vubounds[j] = glb(vuboundss[j]); } Symbol[] tparams = new Symbol[tparams0.length]; for (int j = 0; j < tparams.length; j++) { tparams[j] = tparams0[j].cloneSymbol(Symbol.NONE) .setInfo(hibounds[j].subst(tparams0, tparams)) - .setLoBound(lobounds[j].subst(tparams0, tparams)); + .setLoBound(lobounds[j].subst(tparams0, tparams)) + .setVuBound(vubounds[j].subst(tparams0, tparams)); } return Type.PolyType(tparams, lub(restps).subst(tparams0, tparams)); } @@ -2899,11 +2926,15 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { private static boolean addMember(Scope s, Symbol sym, Type glbThisType) { Type syminfo = sym.info().substThis(sym.owner(), glbThisType); Type symlb = sym.loBound().substThis(sym.owner(), glbThisType); + Type symvb = sym.vuBound().substThis(sym.owner(), glbThisType); Scope.Entry e = s.lookupEntry(sym.name); if (e == Scope.Entry.NONE) { Symbol sym1 = sym.cloneSymbol(glbThisType.symbol()); sym1.setInfo(syminfo); - if (sym1.kind == TYPE) sym1.setLoBound(symlb); + if (sym1.kind == TYPE) { + sym1.setLoBound(symlb); + sym1.setVuBound(symvb); + } s.enter(sym1); } else { Type einfo = e.sym.info(); @@ -2926,6 +2957,14 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { } else { e.sym.setLoBound(lub(new Type[]{elb, symlb})); } + Type evb = e.sym.vuBound(); + if (evb.isSameAs(symvb)) { + } else if (evb.isSubType(symvb)) { + } else if (symvb.isSubType(evb)) { + e.sym.setVuBound(symvb); + } else { + e.sym.setVuBound(glb(new Type[]{evb, symvb})); + } } } return true; @@ -2934,6 +2973,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { private static Type polyGlb(Type[] tps, Symbol[] tparams0) { Type[][] hiboundss = new Type[tparams0.length][tps.length]; Type[][] loboundss = new Type[tparams0.length][tps.length]; + Type[][] vuboundss = new Type[tparams0.length][tps.length]; Type[] restps = new Type[tps.length]; for (int i = 0; i < tps.length; i++) { switch (tps[i]) { @@ -2944,6 +2984,8 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { .subst(tparams, tparams0); loboundss[j][i] = tparams[j].loBound() .subst(tparams, tparams0); + vuboundss[j][i] = tparams[j].vuBound() + .subst(tparams, tparams0); } restps[i] = restp.subst(tparams, tparams0); } else { @@ -2956,15 +2998,18 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { } Type[] hibounds = new Type[tparams0.length]; Type[] lobounds = new Type[tparams0.length]; + Type[] vubounds = new Type[tparams0.length]; for (int j = 0; j < tparams0.length; j++) { hibounds[j] = lub(hiboundss[j]); lobounds[j] = glb(loboundss[j]); + vubounds[j] = lub(vuboundss[j]); } Symbol[] tparams = new Symbol[tparams0.length]; for (int j = 0; j < tparams.length; j++) { tparams[j] = tparams0[j].cloneSymbol(Symbol.NONE) .setInfo(hibounds[j].subst(tparams0, tparams)) - .setLoBound(lobounds[j].subst(tparams0, tparams)); + .setLoBound(lobounds[j].subst(tparams0, tparams)) + .setVuBound(vubounds[j].subst(tparams0, tparams)); } return Type.PolyType(tparams, glb(restps).subst(tparams0, tparams)); } diff --git a/sources/scalac/symtab/classfile/Pickle.java b/sources/scalac/symtab/classfile/Pickle.java index fcf3143da7..2c46855821 100644 --- a/sources/scalac/symtab/classfile/Pickle.java +++ b/sources/scalac/symtab/classfile/Pickle.java @@ -118,15 +118,18 @@ public class Pickle implements Kinds, Modifiers, EntryTags { if (isLocal(sym)) { putEntry(sym.name); putSymbol(sym.isConstructor() ? sym.constructorClass() : sym.owner()); - putType(sym.info()); switch (sym.kind) { case TYPE: + if (sym.isViewBounded()) putType(sym.vuBound()); + else putType(sym.info()); putType(sym.loBound()); break; case ALIAS: + putType(sym.info()); putSymbol(sym.allConstructors()); break; case CLASS: + putType(sym.info()); putType(sym.typeOfThis()); putSymbol(sym.allConstructors()); for (Scope.SymbolIterator it = sym.members().iterator(); @@ -134,6 +137,7 @@ public class Pickle implements Kinds, Modifiers, EntryTags { putSymbol(it.next()); break; case VAL: + putType(sym.info()); if (sym.isConstructor() && sym == sym.constructorClass().allConstructors()) putSymbol(sym.constructorClass()); @@ -336,25 +340,31 @@ public class Pickle implements Kinds, Modifiers, EntryTags { writeRef(sym.name); writeRef(sym.isConstructor() ? sym.constructorClass() : sym.owner()); writeNat(sym.flags); - writeRef(sym.info()); switch (sym.kind) { case TYPE: + if (sym.isViewBounded()) writeRef(sym.vuBound()); + else writeRef(sym.info()); writeRef(sym.loBound()); break; case ALIAS: + writeRef(sym.info()); writeRef(sym.allConstructors()); break; case CLASS: + writeRef(sym.info()); writeRef(sym.typeOfThis()); writeRef(sym.allConstructors()); break; case VAL: + writeRef(sym.info()); if (sym.isConstructor() && sym == sym.constructorClass().allConstructors()) writeRef(sym.constructorClass()); else if (sym.isModule()) writeRef(sym.moduleClass()); break; + default: + throw new ApplicationError(); } } else if (sym.kind == NONE) { writeByte(NONEsym); diff --git a/sources/scalac/symtab/classfile/UnPickle.java b/sources/scalac/symtab/classfile/UnPickle.java index 74a7027424..ba27cbbf60 100644 --- a/sources/scalac/symtab/classfile/UnPickle.java +++ b/sources/scalac/symtab/classfile/UnPickle.java @@ -244,7 +244,12 @@ public class UnPickle implements Kinds, Modifiers, EntryTags, TypeTags { case TYPEsym: entries[n] = sym = owner.newAbstractType( Position.NOPOS, flags, name); - sym.setInfo(getType(inforef, sym)); + if ((flags & VIEWBOUND) != 0) { + sym.setInfo(global.definitions.ANY_TYPE()); + sym.setVuBound(getType(inforef, sym)); + } else { + sym.setInfo(getType(inforef, sym)); + } sym.setLoBound(readTypeRef(sym)); break; diff --git a/sources/scalac/typechecker/RefCheck.java b/sources/scalac/typechecker/RefCheck.java index c7e2572d72..2bb96cbe69 100644 --- a/sources/scalac/typechecker/RefCheck.java +++ b/sources/scalac/typechecker/RefCheck.java @@ -58,6 +58,8 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { // Override checking ------------------------------------------------------------ + static final int HIBOUND = 0, LOBOUND = 1, VUBOUND = 2; + static boolean isIncomplete(Symbol sym) { return sym.isDeferred() || sym.isAbstractOverride() && @@ -255,15 +257,17 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { if (other.typeParams().length != 0) overrideError(pos, member, other, "may not override parameterized type"); if (!self.memberType(member).isSameAs(self.memberType(other))) - overrideTypeError(pos, member, other, self, false); + overrideTypeError(pos, member, other, self, HIBOUND); break; case TYPE: if (member.typeParams().length != 0) overrideError(pos, member, other, "may not be parameterized"); if (!self.memberInfo(member).isSubType(self.memberInfo(other))) - overrideTypeError(pos, member, other, self, false); + overrideTypeError(pos, member, other, self, HIBOUND); if (!self.memberLoBound(other).isSubType(self.memberLoBound(member))) - overrideTypeError(pos, member, other, self, true); + overrideTypeError(pos, member, other, self, LOBOUND); + if (!self.memberVuBound(member).isSubType(self.memberVuBound(other))) + overrideTypeError(pos, member, other, self, VUBOUND); break; default: if (other.isConstructor()) @@ -271,7 +275,7 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { "cannot override a class constructor"); if (!normalizedInfo(self, member).isSubType( normalizedInfo(self, other))) - overrideTypeError(pos, member, other, self, false); + overrideTypeError(pos, member, other, self, HIBOUND); } } } @@ -284,17 +288,25 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { } void overrideTypeError(int pos, Symbol member, Symbol other, Type site, - boolean lobound) { + int boundkind) { if (!other.type().isError() && !member.type().isError()) { - Type memberInfo = lobound ? site.memberLoBound(member) - : normalizedInfo(site, member); - Type otherInfo = lobound ? site.memberLoBound(other) - : normalizedInfo(site, other); + Type memberInfo; + Type otherInfo; + if (boundkind == LOBOUND) { + memberInfo = site.memberLoBound(member); + otherInfo = site.memberLoBound(other); + } else if (boundkind == VUBOUND) { + memberInfo = site.memberVuBound(member); + otherInfo = site.memberVuBound(other); + } else { + memberInfo = normalizedInfo(site, member); + otherInfo = normalizedInfo(site, other); + } unit.error(pos, member + member.locationString() + - infoString(member, memberInfo, lobound) + + infoString(member, memberInfo, boundkind) + "\n cannot override " + other + other.locationString() + - infoString(other, otherInfo, lobound)); + infoString(other, otherInfo, boundkind)); Type.explainTypes(memberInfo, otherInfo); } } @@ -303,10 +315,10 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { return site.memberInfo(sym).derefDef(); } - String infoString(Symbol sym, Type symtype, boolean lobound) { + String infoString(Symbol sym, Type symtype, int boundkind) { switch (sym.kind) { case ALIAS: return ", which equals " + symtype; - case TYPE: return " bounded" + (lobound ? " from below" : "") + " by " + symtype; + case TYPE: return " bounded" + (boundkind == LOBOUND ? " from below" : "") + " by " + symtype; case VAL: return " of type " + symtype; default: return ""; } @@ -956,6 +968,7 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { case AbsTypeDef(_, _, _, _): validateVariance(sym, sym.info(), CoVariance); validateVariance(sym, sym.loBound(), ContraVariance); + validateVariance(sym, sym.vuBound(), CoVariance); return super.transform(tree); case AliasTypeDef(_, _, _, _): diff --git a/test/files/pos/exceptions.scala b/test/files/pos/exceptions.scala index 2ba15efb4a..819368244d 100644 --- a/test/files/pos/exceptions.scala +++ b/test/files/pos/exceptions.scala @@ -17,5 +17,4 @@ object Test { case ex => System.out.println(ex); } } - } -- cgit v1.2.3