diff options
author | Martin Odersky <odersky@gmail.com> | 2007-08-29 15:57:30 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2007-08-29 15:57:30 +0000 |
commit | 10bd9e9c8ea541b22ed87319e04f957621b20de7 (patch) | |
tree | 6a0fd9808d1259395a14fad4a9d162b668608ffd | |
parent | 840202e705c9d13ee59515fde29543db81bcea9c (diff) | |
download | scala-10bd9e9c8ea541b22ed87319e04f957621b20de7.tar.gz scala-10bd9e9c8ea541b22ed87319e04f957621b20de7.tar.bz2 scala-10bd9e9c8ea541b22ed87319e04f957621b20de7.zip |
fix^2 of defect 15.
4 files changed, 88 insertions, 29 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index f9ee9755d0..ef29cf04f9 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -15,6 +15,8 @@ abstract class TreePrinters { val trees: Trees import trees._ + final val showOuterTests = false + class TreePrinter(out: PrintWriter) { protected var indentMargin = 0 protected val indentStep = 2 @@ -125,6 +127,9 @@ abstract class TreePrinters { def print(str: String) { out.print(str) } def print(name: Name) { print(name.toString()) } + private var currentOwner: Symbol = NoSymbol + private var selectorType: Type = NoType + def printRaw(tree: Tree) { tree match { case EmptyTree => @@ -199,6 +204,8 @@ abstract class TreePrinters { mkString("{", ",", "}")) case Template(parents, self, body) => + val currentOwner1 = currentOwner + if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner printRow(parents, " with ") if (!body.isEmpty) { if (self.name != nme.WILDCARD) { @@ -210,15 +217,28 @@ abstract class TreePrinters { } printColumn(body, "", ";", "}") } + currentOwner = currentOwner1 case Block(stats, expr) => printColumn(stats ::: List(expr), "{", ";", "}") case Match(selector, cases) => + val selectorType1 = selectorType + selectorType = selector.tpe print(selector); printColumn(cases, " match {", "", "}") + selectorType = selectorType1 case CaseDef(pat, guard, body) => - print("case "); print(pat); printOpt(" if ", guard) + print("case "); + def patConstr(pat: Tree): Tree = pat match { + case Apply(fn, args) => patConstr(fn) + case _ => pat + } + if (showOuterTests && + needsOuterTest( + patConstr(pat).tpe.finalResultType, selectorType, currentOwner)) + print("???") + print(pat); printOpt(" if ", guard) print(" => "); print(body) case Sequence(trees) => diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 97a037c8de..a634233d74 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -2713,6 +2713,69 @@ A type's typeSymbol should never be inspected directly. ok } + /** Is intersection of given types populated? That is, + * for all types tp1, tp2 in intersection + * for all common base classes bc of tp1 and tp2 + * let bt1, bt2 be the base types of tp1, tp2 relative to class bc + * Then: + * bt1 and bt2 have the same prefix, and + * any correspondiong non-variant type arguments of bt1 and bt2 are the same + */ + def isPopulated(tp1: Type, tp2: Type): Boolean = { + def isConsistent(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { + case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => + assert(sym1 == sym2) + pre1 =:= pre2 && + !(List.map3(args1, args2, sym1.typeParams) { + (arg1, arg2, tparam) => + //if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG + tparam.variance != 0 || arg1 =:= arg2 + } contains false) + } + if (tp1.typeSymbol.isClass && tp1.typeSymbol.hasFlag(FINAL)) + tp1 <:< tp2 || isNumericValueClass(tp1.typeSymbol) && isNumericValueClass(tp2.typeSymbol) + else tp1.baseClasses forall (bc => + tp2.closurePos(bc) < 0 || isConsistent(tp1.baseType(bc), tp2.baseType(bc))) + } + + /** Does a pattern of type `patType' need an outer test when executed against + * selector type `selType' in context defined by `currentOwner'? + */ + def needsOuterTest(patType: Type, selType: Type, currentOwner: Symbol) = { + def createDummyClone(pre: Type): Type = { + val dummy = currentOwner.enclClass.newValue(NoPosition, nme.ANYNAME).setInfo(pre.widen) + singleType(ThisType(currentOwner.enclClass), dummy) + } + def maybeCreateDummyClone(pre: Type, sym: Symbol): Type = pre match { + case SingleType(pre1, sym1) => + if (sym1.isModule && sym1.isStatic) { + NoType + } else if (sym1.isModule && sym.owner == sym1.moduleClass) { + val pre2 = maybeCreateDummyClone(pre1, sym1) + if (pre2 eq NoType) pre2 + else singleType(pre2, sym1) + } else { + createDummyClone(pre) + } + case ThisType(clazz) => + if (clazz.isModuleClass) + maybeCreateDummyClone(clazz.typeOfThis, sym) + else if (sym.owner == clazz && (sym.hasFlag(PRIVATE) || sym.privateWithin == clazz)) + NoType + else + createDummyClone(pre) + case _ => + NoType + } + patType match { + case TypeRef(pre, sym, args) => + val pre1 = maybeCreateDummyClone(pre, sym) + (pre1 ne NoType) && isPopulated(typeRef(pre1, sym, args), selType) + case _ => + false + } + } + /** Undo all changes to constraints to type variables upto `limit' */ private def undoTo(limit: UndoLog) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 11b8d555c0..beaa2ac5af 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -804,31 +804,6 @@ trait Infer { } } - /** Is intersection of given types populated? That is, - * for all types tp1, tp2 in intersection - * for all common base classes bc of tp1 and tp2 - * let bt1, bt2 be the base types of tp1, tp2 relative to class bc - * Then: - * bt1 and bt2 have the same prefix, and - * any correspondiong non-variant type arguments of bt1 and bt2 are the same - */ - def isPopulated(tp1: Type, tp2: Type): Boolean = { - def isConsistent(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { - case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => - assert(sym1 == sym2) - pre1 =:= pre2 && - !(List.map3(args1, args2, sym1.typeParams) { - (arg1, arg2, tparam) => - //if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG - tparam.variance != 0 || arg1 =:= arg2 - } contains false) - } - if (tp1.typeSymbol.isClass && tp1.typeSymbol.hasFlag(FINAL)) - tp1 <:< tp2 || isNumericValueClass(tp1.typeSymbol) && isNumericValueClass(tp2.typeSymbol) - else tp1.baseClasses forall (bc => - tp2.closurePos(bc) < 0 || isConsistent(tp1.baseType(bc), tp2.baseType(bc))) - } - /** Type with all top-level occurrences of abstract types replaced by their bounds */ def widen(tp: Type): Type = tp match { // @M don't normalize here (compiler loops on pos/bug1090.scala ) case TypeRef(_, sym, _) if sym.isAbstractType => diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index b9a95c84db..3909b42ead 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2601,7 +2601,7 @@ trait Typers { self: Analyzer => } } if (defSym.owner.isPackageClass) pre = defSym.owner.thisType - if (defSym.isThisSym) typed1(This(defSym.owner), mode, pt) + if (defSym.isThisSym) typed1(This(defSym.owner) setPos tree.pos, mode, pt) else { val tree1 = if (qual == EmptyTree) tree else atPos(tree.pos)(Select(qual, name)) @@ -2946,10 +2946,11 @@ trait Typers { self: Analyzer => if (tp1 eq tp0) tp else tp1 case _ => tp } +// Console.println("typing "+tree+" at "+tree.pos);//DEBUG var tree1 = if (tree.tpe ne null) tree else typed1(tree, mode, dropExistential(pt)) - //Console.println("typed "+tree1+":"+tree1.tpe+", "+context.undetparams);//DEBUG +// Console.println("typed "+tree1+":"+tree1.tpe+", "+context.undetparams);//DEBUG val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt) - //Console.println("adapted "+tree1+":"+tree1.tpe+" to "+pt+", "+context.undetparams);//DEBUG +// Console.println("adapted "+tree1+":"+tree1.tpe+" to "+pt+", "+context.undetparams);//DEBUG // if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe) result } catch { |