diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/reflect/internal/Types.scala | 40 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Implicits.scala | 48 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 50 |
3 files changed, 55 insertions, 83 deletions
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 43905ee344..6d4332216c 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -943,30 +943,12 @@ trait Types extends api.Types { self: SymbolTable => */ //TODO: use narrow only for modules? (correct? efficiency gain?) def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean): Symbol = { - var suspension: mutable.HashSet[TypeVar] = null // if this type contains type variables, put them to sleep for a while -- don't just wipe them out by // replacing them by the corresponding type parameter, as that messes up (e.g.) type variables in type refinements // without this, the matchesType call would lead to type variables on both sides // of a subtyping/equality judgement, which can lead to recursive types being constructed. // See (t0851) for a situation where this happens. - if (!this.isGround) { - // PP: The foreach below was formerly expressed as: - // for(tv @ TypeVar(_, _) <- this) { suspension suspend tv } - // - // The tree checker failed this saying a TypeVar is required, but a (Type @unchecked) was found. - // This is a consequence of using a pattern match and variable binding + ticket #1503, which - // was addressed by weakening the type of bindings in pattern matches if they occur on the right. - // So I'm not quite sure why this works at all, as the checker is right that it is mistyped. - // For now I modified it as below, which achieves the same without error. - // - // make each type var in this type use its original type for comparisons instead of collecting constraints - val susp = new mutable.HashSet[TypeVar] // use a local val so it remains unboxed - this foreach { - case tv: TypeVar => tv.suspended = true; susp += tv - case _ => - } - suspension = susp - } + val suspension: List[TypeVar] = if (this.isGround) null else suspendTypeVarsInType(this) incCounter(findMemberCount) val start = startTimer(findMemberNanos) @@ -6101,6 +6083,26 @@ trait Types extends api.Types { self: SymbolTable => if (ts exists (_.isNotNull)) res.notNull else res } + + /** A list of the typevars in a type. */ + def typeVarsInType(tp: Type): List[TypeVar] = { + var tvs: List[TypeVar] = Nil + tp foreach { + case t: TypeVar => tvs ::= t + case _ => + } + tvs.reverse + } + /** Make each type var in this type use its original type for comparisons instead + * of collecting constraints. + */ + def suspendTypeVarsInType(tp: Type): List[TypeVar] = { + val tvs = typeVarsInType(tp) + // !!! Is it somehow guaranteed that this will not break under nesting? + // In general one has to save and restore the contents of the field... + tvs foreach (_.suspended = true) + tvs + } /** Compute lub (if `variance == 1`) or glb (if `variance == -1`) of given list * of types `tps`. All types in `tps` are typerefs or singletypes diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 3b90eaeed7..918eb749c8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -45,8 +45,9 @@ trait Implicits { * @return A search result */ def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context): SearchResult = { - printInference("[inferImplicit%s] pt = %s".format( - if (isView) " view" else "", pt) + printInference("[infer %s] %s with pt=%s in %s".format( + if (isView) "view" else "implicit", + tree, pt, context.owner.enclClass) ) printTyping( ptBlock("infer implicit" + (if (isView) " view" else ""), @@ -65,7 +66,7 @@ trait Implicits { printTyping("typing implicit: %s %s".format(tree, context.undetparamsString)) val result = new ImplicitSearch(tree, pt, isView, context.makeImplicit(reportAmbiguous)).bestImplicit - printInference("[inferImplicit] result: " + result) + printInference("[infer implicit] inferred " + result) context.undetparams = context.undetparams filterNot result.subst.from.contains stopTimer(implicitNanos, start) @@ -395,7 +396,6 @@ trait Implicits { * @pre `info.tpe` does not contain an error */ private def typedImplicit(info: ImplicitInfo, ptChecked: Boolean): SearchResult = { - printInference("[typedImplicit] " + info) (context.openImplicits find { case (tp, sym) => sym == tree.symbol && dominates(pt, tp)}) match { case Some(pending) => // println("Pending implicit "+pending+" dominates "+pt+"/"+undetParams) //@MDEBUG @@ -614,16 +614,15 @@ trait Implicits { info.sym.fullLocationString, itree1.symbol.fullLocationString)) else { val tvars = undetParams map freshVar - - if (matchesPt(itree2.tpe, pt.instantiateTypeParams(undetParams, tvars), undetParams)) { - printInference( - ptBlock("matchesPt", - "itree1" -> itree1, - "tvars" -> tvars, - "undetParams" -> undetParams - ) - ) - + def ptInstantiated = pt.instantiateTypeParams(undetParams, tvars) + + printInference("[search] considering %s (pt contains %s) trying %s against pt=%s".format( + if (undetParams.isEmpty) "no tparams" else undetParams.map(_.name).mkString(", "), + typeVarsInType(ptInstantiated) filterNot (_.isGround) match { case Nil => "no tvars" ; case tvs => tvs.mkString(", ") }, + itree2.tpe, pt + )) + + if (matchesPt(itree2.tpe, ptInstantiated, undetParams)) { if (tvars.nonEmpty) printTyping(ptLine("" + info.sym, "tvars" -> tvars, "tvars.constr" -> tvars.map(_.constr))) @@ -637,6 +636,7 @@ trait Implicits { // we must be conservative in leaving type params in undetparams // prototype == WildcardType: want to remove all inferred Nothings val AdjustedTypeArgs(okParams, okArgs) = adjustTypeArgs(undetParams, tvars, targs) + val subst: TreeTypeSubstituter = if (okParams.isEmpty) EmptyTreeTypeSubstituter else { @@ -663,11 +663,10 @@ trait Implicits { } val result = new SearchResult(itree2, subst) incCounter(foundImplicits) - printInference("[typedImplicit1] SearchResult: " + result) + printInference("[success] found %s for pt %s".format(result, ptInstantiated)) result } - else fail("incompatible: %s does not match expected type %s".format( - itree2.tpe, pt.instantiateTypeParams(undetParams, tvars))) + else fail("incompatible: %s does not match expected type %s".format(itree2.tpe, ptInstantiated)) } } catch { @@ -786,16 +785,11 @@ trait Implicits { // most frequent one first matches sortBy (x => if (isView) -x.useCountView else -x.useCountArg) } - def eligibleString = { - val args = List( - "search" -> pt, - "target" -> tree, - "isView" -> isView - ) ++ eligible.map("eligible" -> _) - - ptBlock("Implicit search in " + context, args: _*) - } - printInference(eligibleString) + if (eligible.nonEmpty) + printInference("[search%s] %s with pt=%s in %s, eligible:\n %s".format( + if (isView) " view" else "", + tree, pt, context.owner.enclClass, eligible.mkString("\n ")) + ) /** Faster implicit search. Overall idea: * - prune aggressively diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 23dd28aac4..b1612f24ef 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -138,6 +138,9 @@ trait Infer { def solvedTypes(tvars: List[TypeVar], tparams: List[Symbol], variances: List[Int], upper: Boolean, depth: Int): List[Type] = { + if (tvars.nonEmpty) + printInference("[solve types] solving for " + tparams.map(_.name).mkString(", ") + " in " + tvars.mkString(", ")) + 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. *ZAP* @M danger, Will Robinson! this means @@ -550,18 +553,6 @@ trait Infer { throw new NoInstance("parameter lists differ in length") val restpeInst = restpe.instantiateTypeParams(tparams, tvars) - printInference( - ptBlock("methTypeArgs", - "tparams" -> tparams, - "formals" -> formals, - "restpe" -> restpe, - "restpeInst" -> restpeInst, - "argtpes" -> argtpes, - "pt" -> pt, - "tvars" -> tvars, - "constraints" -> tvars.map(_.constr) - ) - ) // first check if typevars can be fully defined from the expected type. // The return value isn't used so I'm making it obvious that this side @@ -599,17 +590,7 @@ trait Infer { tvars, tparams, tparams map varianceInTypes(formals), false, lubDepth(formals) max lubDepth(argtpes) ) - val result = adjustTypeArgs(tparams, tvars, targs, restpe) - - printInference( - ptBlock("methTypeArgs result", - "tvars" -> tvars, - "constraints" -> tvars.map(_.constr), - "targs" -> targs, - "adjusted type args" -> result - ) - ) - result + adjustTypeArgs(tparams, tvars, targs, restpe) } private[typechecker] def followApply(tp: Type): Type = tp match { @@ -1094,15 +1075,6 @@ trait Infer { def inferMethodInstance(fn: Tree, undetparams: List[Symbol], args: List[Tree], pt0: Type): List[Symbol] = fn.tpe match { case MethodType(params0, _) => - printInference( - ptBlock("inferMethodInstance", - "fn" -> fn, - "undetparams" -> undetparams, - "args" -> args, - "pt0" -> pt0 - ) - ) - try { val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 val formals = formalTypes(params0 map (_.tpe), args.length) @@ -1112,11 +1084,19 @@ trait Infer { val AdjustedTypeArgs.AllArgsAndUndets(okparams, okargs, allargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, argtpes, pt) + printInference("[infer method] solving for %s in %s based on (%s)%s (%s)".format( + undetparams.map(_.name).mkString(", "), + fn.tpe, + argtpes.mkString(", "), + restpe, + (okparams map (_.name), okargs).zipped.map(_ + "=" + _).mkString("solved: ", ", ", "") + )) + checkBounds(fn.pos, NoPrefix, NoSymbol, undetparams, allargs, "inferred ") val treeSubst = new TreeTypeSubstituter(okparams, okargs) treeSubst traverseTrees fn :: args - val result = leftUndet match { + leftUndet match { case Nil => Nil case xs => // #3890 @@ -1126,10 +1106,6 @@ trait Infer { xs1 } - if (result.nonEmpty) - printInference("inferMethodInstance, still undetermined: " + result) - - result } catch ifNoInstance { msg => errorTree(fn, "no type parameters for " + |