From 60963bf600b282a1978aed96cbb5edcdba6c1709 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 1 Aug 2008 18:31:47 +0000 Subject: Fixed #1049 and #1062 --- .../scala/tools/nsc/symtab/BaseTypeSeqs.scala | 33 +++++++- src/compiler/scala/tools/nsc/symtab/Types.scala | 91 ++++++++-------------- .../scala/tools/nsc/typechecker/Infer.scala | 15 ++-- .../scala/tools/nsc/typechecker/Typers.scala | 12 ++- 4 files changed, 78 insertions(+), 73 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala index c1c251c9bd..f7b3d77d41 100755 --- a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala +++ b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala @@ -5,7 +5,7 @@ package scala.tools.nsc.symtab import scala.collection.mutable.ListBuffer -import util.BitSet +import Math.max /** A base type sequence (BaseTypeSeq) is an ordered sequence spanning all the base types * of a type. It characterized by the following two laws: @@ -23,7 +23,7 @@ import util.BitSet * to avoid confusion with function closures. */ trait BaseTypeSeqs { - self: SymbolTable => + this: SymbolTable => import definitions._ class BaseTypeSeq(parents: List[Type], elems: Array[Type]) { @@ -42,7 +42,7 @@ trait BaseTypeSeqs { //Console.println("compute closure of "+this+" => glb("+variants+")") elems(i) = NoType try { - mergePrefixAndArgs(variants, -1, maxBaseTypeSeqDepth(variants) + LubGlbMargin) match { + mergePrefixAndArgs(variants, -1, lubDepth(variants)) match { case Some(tp0) => elems(i) = tp0 tp0 @@ -126,7 +126,32 @@ trait BaseTypeSeqs { */ lazy val maxDepth: Int = { var d = 0 - for (i <- 0 until length) d = Math.max(d, self.maxDepth(elems(i))) + for (i <- 0 until length) d = Math.max(d, maxDpth(elems(i))) + d + } + + /** The maximum depth of type `tp' */ + private def maxDpth(tp: Type): Int = tp match { + case TypeRef(pre, sym, args) => + max(maxDpth(pre), maxDpth(args) + 1) + case RefinedType(parents, decls) => + max(maxDpth(parents), maxDpth(decls.toList.map(_.info)) + 1) + case TypeBounds(lo, hi) => + max(maxDpth(lo), maxDpth(hi)) + case MethodType(paramtypes, result) => + maxDpth(result) + case PolyType(tparams, result) => + max(maxDpth(result), maxDpth(tparams map (_.info)) + 1) + case ExistentialType(tparams, result) => + max(maxDpth(result), maxDpth(tparams map (_.info)) + 1) + case _ => + 1 + } + + /** The maximum depth of all types `tps' */ + private def maxDpth(tps: Seq[Type]): Int = { + var d = 0 + for (tp <- tps) d = max(d, maxDpth(tp)) d } diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 87c60d3781..fe36c0a3b4 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -78,7 +78,6 @@ trait Types { private var explainSwitch = false private var checkMalformedSwitch = false // todo: it's now always false. Remove all code that depends on this switch. - final val LubGlbMargin = 0 private final val LogPendingSubTypesThreshold = 50 private final val LogPendingBaseTypesThreshold = 50 @@ -88,6 +87,8 @@ trait Types { /** Decrement depth unless it is a don't care */ private final def decr(depth: Int) = if (depth == AnyDepth) AnyDepth else depth - 1 + private final val printLubs = false + /** The current skolemization level, needed for the algorithms * in isSameType, isSubType that do constraint solving under a prefix */ @@ -3168,44 +3169,22 @@ A type's typeSymbol should never be inspected directly. // Helper Methods ------------------------------------------------------------- - import Math.max - private var nextid = 0 private def freshName() = { nextid += 1 "_"+nextid } - /** The maximum depth of all types in the base type sequences of each of the types `tps' */ - final def maxBaseTypeSeqDepth(tps: Seq[Type]): Int = { - var d = 0 - for (tp <- tps) d = max(d, tp.baseTypeSeqDepth) - d - } + final val LubGlbMargin = 0 - /** The maximum depth of all types `tps' */ - final def maxDepth(tps: Seq[Type]): Int = { + /** The maximum allowable depth of lubs or glbs over types `ts' + * This is the maximum depth of all types in the base type sequences + * of each of the types `ts', plus LubGlbMargin + */ + def lubDepth(ts: List[Type]) = { var d = 0 - for (tp <- tps) d = max(d, maxDepth(tp)) - d - } - - /** The maximum depth of type `tp' */ - final def maxDepth(tp: Type): Int = tp match { - case TypeRef(pre, sym, args) => - max(maxDepth(pre), maxDepth(args) + 1) - case RefinedType(parents, decls) => - max(maxDepth(parents), maxDepth(decls.toList.map(_.info)) + 1) - case TypeBounds(lo, hi) => - max(maxDepth(lo), maxDepth(hi)) - case MethodType(paramtypes, result) => - maxDepth(result) - case PolyType(tparams, result) => - max(maxDepth(result), maxDepth(tparams map (_.info)) + 1) - case ExistentialType(tparams, result) => - max(maxDepth(result), maxDepth(tparams map (_.info)) + 1) - case _ => - 1 + for (tp <- ts) d = Math.max(d, tp.baseTypeSeqDepth) + d + LubGlbMargin } final def isValid(period: Period): Boolean = @@ -3634,16 +3613,8 @@ A type's typeSymbol should never be inspected directly. } finally { skolemizationLevel -= 1 } - case (RefinedType(parents1, ref1), _: ExistentialType) - if (parents1 exists (_.isInstanceOf[ExistentialType])) => - try { - skolemizationLevel += 1 - RefinedType(parents1 map (_.skolemizeExistential(NoSymbol, null)), ref1) <:< tp2 - } finally { - skolemizationLevel -= 1 - } - case (_, et: ExistentialType) => - et.withTypeVars(tp1 <:< _, depth) + case (_, et: ExistentialType) if et.withTypeVars(tp1 <:< _, depth) => + true case (RefinedType(parents1, ref1), _) => parents1 exists (_ <:< tp2) @@ -3954,7 +3925,7 @@ A type's typeSymbol should never be inspected directly. (strippedTypes, quantified) } - def lub(ts: List[Type]): Type = lub(ts, maxBaseTypeSeqDepth(ts) + LubGlbMargin) + def lub(ts: List[Type]): Type = lub(ts, lubDepth(ts)) /** The least upper bound wrt <:< of a list of types */ def lub(ts: List[Type], depth: Int): Type = { @@ -4032,22 +4003,22 @@ A type's typeSymbol should never be inspected directly. } existentialAbstraction(tparams, lubType) } -// if (settings.debug.value) { -// println(indent + "lub of " + ts + " at depth "+depth)//debug -// indent = indent + " " -// assert(indent.length <= 100) -// } + if (printLubs) { + println(indent + "lub of " + ts + " at depth "+depth)//debug + indent = indent + " " + assert(indent.length <= 100) + } val res = if (depth < 0) AnyClass.tpe else lub0(ts) -// if (settings.debug.value) { -// indent = indent.substring(0, indent.length() - 2) -// println(indent + "lub of " + ts + " is " + res)//debug -// } + if (printLubs) { + indent = indent.substring(0, indent.length() - 2) + println(indent + "lub of " + ts + " is " + res)//debug + } if (ts forall (_.isNotNull)) res.notNull else res } val GlbFailure = new Throwable - def glb(ts: List[Type]): Type = glb(ts, maxBaseTypeSeqDepth(ts) + LubGlbMargin) + def glb(ts: List[Type]): Type = glb(ts, lubDepth(ts)) /** The greatest lower bound wrt <:< of a list of types */ private def glb(ts: List[Type], depth: Int): Type = { @@ -4127,15 +4098,15 @@ A type's typeSymbol should never be inspected directly. else NothingClass.tpe } } -// if (settings.debug.value) { -// log(indent + "glb of " + ts + " at depth "+depth)//debug -// indent = indent + " " -// } + if (settings.debug.value) { + println(indent + "glb of " + ts + " at depth "+depth)//debug + indent = indent + " " + } val res = if (depth < 0) NothingClass.tpe else glb0(ts) -// if (settings.debug.value) { -// indent = indent.substring(0, indent.length() - 2) -// log(indent + "glb of " + ts + " is " + res)//debug -// } + if (settings.debug.value) { + indent = indent.substring(0, indent.length() - 2) + log(indent + "glb of " + ts + " is " + res)//debug + } if (ts exists (_.isNotNull)) res.notNull else res } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 5e77092248..d83b581394 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -143,12 +143,12 @@ trait Infer { * @throws NoInstance */ private def solvedTypes(tvars: List[TypeVar], tparams: List[Symbol], - variances: List[Int], upper: Boolean): List[Type] = { + variances: List[Int], upper: Boolean, depth: Int): List[Type] = { def boundsString(tvar: TypeVar) = "\n "+ ((tvar.constr.lobounds map (_ + " <: " + tvar.origin.typeSymbol.name)) ::: (tvar.constr.hibounds map (tvar.origin.typeSymbol.name + " <: " + _)) mkString ", ") - if (!solve(tvars, tparams, variances, upper)) { + if (!solve(tvars, tparams, variances, upper, depth)) { // no panic, it's good enough to just guess a solution, we'll find out // later whether it works. // throw new DeferredNoInstance(() => @@ -448,7 +448,8 @@ trait Infer { val tvars = tparams map freshVar if (isCompatible(restpe.instantiateTypeParams(tparams, tvars), pt)) { try { - solvedTypes(tvars, tparams, tparams map varianceInType(restpe), false) + solvedTypes(tvars, tparams, tparams map varianceInType(restpe), + false, lubDepth(List(restpe, pt))) } catch { case ex: NoInstance => null } @@ -535,7 +536,7 @@ trait Infer { // check first whether type variables can be fully defined from // expected result type. if (!isWeaklyCompatible(restpe.instantiateTypeParams(tparams, tvars), pt)) { -// just wait and instantiate form the arguments. +// just wait and instantiate from the arguments. // that way, we can try to apply an implicit conversion afterwards. // This case could happen if restpe is not fully defined, so that // search for an implicit from it to pt fails because of an ambiguity. @@ -556,7 +557,8 @@ trait Infer { } () } - val targs = solvedTypes(tvars, tparams, tparams map varianceInTypes(formals), false) + val targs = solvedTypes(tvars, tparams, tparams map varianceInTypes(formals), + false, lubDepth(formals) max lubDepth(argtpes)) // val res = List.map2(tparams, targs) {(tparam, targ) => if (targ.typeSymbol == NothingClass && (varianceInType(restpe)(tparam) & COVARIANT) == 0) { @@ -1007,7 +1009,8 @@ trait Infer { */ def computeArgs = try { - val targs = solvedTypes(tvars, undetparams, undetparams map varianceInType(restpe), true) + val targs = solvedTypes(tvars, undetparams, undetparams map varianceInType(restpe), + true, lubDepth(List(restpe, pt))) // checkBounds(tree.pos, NoPrefix, NoSymbol, undetparams, targs, "inferred ") // no checkBounds here. If we enable it, test bug602 fails. new TreeTypeSubstituter(undetparams, targs).traverse(tree) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 97275ad526..042b7293bb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -28,6 +28,8 @@ trait Typers { self: Analyzer => import definitions._ import posAssigner.atPos + private final val printTypings = false + var appcnt = 0 var idcnt = 0 var selcnt = 0 @@ -2319,6 +2321,10 @@ trait Typers { self: Analyzer => error(tree.pos, "illegal variable in pattern alternative") vble = namer.enterInScope(vble) } + vble.setInfo(new LazyType { + // forces a cyclic reference error when dereferenced. See #1049 + override def complete(sym: Symbol) { sym.info } + }) val body1 = typed(body, mode, pt) trackSetInfo(vble)( if (treeInfo.isSequenceValued(body)) seqType(body1.tpe) @@ -3285,7 +3291,7 @@ trait Typers { self: Analyzer => tree.tpe = null if (tree.hasSymbol) tree.symbol = NoSymbol } -// Console.println("typing "+tree+", "+context.undetparams);//DEBUG + if (printTypings) println("typing "+tree+", "+context.undetparams);//DEBUG def dropExistential(tp: Type): Type = tp match { case ExistentialType(tparams, tpe) => if (settings.debug.value) println("drop ex "+tree+" "+tp) @@ -3297,12 +3303,12 @@ trait Typers { self: Analyzer => case _ => tp } var tree1 = if (tree.tpe ne null) tree else typed1(tree, mode, dropExistential(pt)) -// Console.println("typed "+tree1+":"+tree1.tpe+", "+context.undetparams+", pt = "+pt);//DEBUG + if (printTypings) println("typed "+tree1+":"+tree1.tpe+", "+context.undetparams+", pt = "+pt);//DEBUG tree1.tpe = addAnnotations(tree1, tree1.tpe) val result = if (tree1.isEmpty || (inIDE && tree1.tpe == null)) tree1 else adapt(tree1, mode, pt) -// Console.println("adapted "+tree1+":"+tree1.tpe+" to "+pt+", "+context.undetparams);//DEBUG + if (printTypings) println("adapted "+tree1+":"+tree1.tpe+" to "+pt+", "+context.undetparams);//DEBUG // if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe) result } catch { -- cgit v1.2.3