diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Implicits.scala | 23 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 13 | ||||
-rw-r--r-- | test/files/pos/nothing_manifest_disambig.scala | 10 |
3 files changed, 29 insertions, 17 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 7452ac678b..a6549021c5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -27,6 +27,7 @@ self: Analyzer => import definitions._ def traceImplicits = printTypings + import global.typer.{printTyping, deindentTyping, indentTyping} /** Search for an implicit value. See the comment on `result` at the end of class `ImplicitSearch` * for more info how the search is conducted. @@ -42,6 +43,8 @@ self: Analyzer => * @return A search result */ def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context): SearchResult = { + printTyping("Beginning implicit search for "+ tree +" expecting "+ pt + (if(isView) " looking for a view" else "")) + indentTyping() val rawTypeStart = startCounter(rawTypeImpl) val findMemberStart = startCounter(findMemberImpl) val subtypeStart = startCounter(subtypeImpl) @@ -54,6 +57,8 @@ self: Analyzer => stopCounter(rawTypeImpl, rawTypeStart) stopCounter(findMemberImpl, findMemberStart) stopCounter(subtypeImpl, subtypeStart) + deindentTyping() + printTyping("Implicit search yielded: "+ result) result } @@ -209,11 +214,10 @@ self: Analyzer => */ class ImplicitSearch(tree: Tree, pt: Type, isView: Boolean, context0: Context) extends Typer(context0) { - + printTyping("begin implicit search: "+(tree, pt, isView, context.outer.undetparams)) // assert(tree.isEmpty || tree.pos.isDefined, tree) import infer._ - /** Is implicit info `info1` better than implicit info `info2`? */ def improves(info1: ImplicitInfo, info2: ImplicitInfo) = { @@ -424,7 +428,7 @@ self: Analyzer => incCounter(plausiblyCompatibleImplicits) - //if (traceImplicits) println("typed impl for "+wildPt+"? "+info.name+":"+depoly(info.tpe)+"/"+undetParams+"/"+isPlausiblyCompatible(info.tpe, wildPt)+"/"+matchesPt(depoly(info.tpe), wildPt, List())+"/"+info.pre+"/"+isStable(info.pre)) + printTyping("typed impl for "+wildPt+"? "+info.name +":"+ depoly(info.tpe)+ " orig info= "+ info.tpe +"/"+undetParams+"/"+isPlausiblyCompatible(info.tpe, wildPt)+"/"+matchesPt(depoly(info.tpe), wildPt, List())+"/"+info.pre+"/"+isStable(info.pre)) if (matchesPt(depoly(info.tpe), wildPt, List()) && isStable(info.pre)) { incCounter(matchingImplicits) @@ -433,7 +437,7 @@ self: Analyzer => if (info.pre == NoPrefix) Ident(info.name) else Select(gen.mkAttributedQualifier(info.pre), info.name) } - if (traceImplicits) println("typed impl?? "+info.name+":"+info.tpe+" ==> "+itree+" with pt = "+pt+", wildpt = "+wildPt) + printTyping("typedImplicit0 typing"+ itree +" with wildpt = "+ wildPt +" from implicit "+ info.name+":"+info.tpe) def fail(reason: String): SearchResult = { if (settings.XlogImplicits.value) inform(itree+" is not a valid implicit value for "+pt+" because:\n"+reason) @@ -452,10 +456,10 @@ self: Analyzer => incCounter(typedImplicits) - if (traceImplicits) println("typed implicit "+itree1+":"+itree1.tpe+", pt = "+wildPt) + printTyping("typed implicit "+itree1+":"+itree1.tpe+", pt = "+wildPt) val itree2 = if (isView) (itree1: @unchecked) match { case Apply(fun, _) => fun } else adapt(itree1, EXPRmode, wildPt) - if (traceImplicits) println("adapted implicit "+itree1.symbol+":"+itree2.tpe+" to "+wildPt) + printTyping("adapted implicit "+itree1.symbol+":"+itree2.tpe+" to "+wildPt) def hasMatchingSymbol(tree: Tree): Boolean = (tree.symbol == info.sym) || { tree match { case Apply(fun, _) => hasMatchingSymbol(fun) @@ -469,7 +473,7 @@ self: Analyzer => else if (hasMatchingSymbol(itree1)) { val tvars = undetParams map freshVar if (matchesPt(itree2.tpe, pt.instantiateTypeParams(undetParams, tvars), undetParams)) { - if (traceImplicits) println("tvars = "+tvars+"/"+(tvars map (_.constr))) + printTyping("tvars = "+tvars+"/"+(tvars map (_.constr))) val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt), false, lubDepth(List(itree2.tpe, pt))) @@ -498,7 +502,8 @@ self: Analyzer => // println("RESULT = "+itree+"///"+itree1+"///"+itree2)//DEBUG result } else { - if (traceImplicits) println("incompatible: "+itree2.tpe+" does not match "+pt.instantiateTypeParams(undetParams, tvars)) + printTyping("incompatible: "+itree2.tpe+" does not match "+pt.instantiateTypeParams(undetParams, tvars)) + SearchFailure } } else if (settings.XlogImplicits.value) @@ -840,6 +845,8 @@ self: Analyzer => } else if (sym.isExistentiallyBound && full) { manifestFactoryCall("wildcardType", tp, findManifest(tp.bounds.lo), findManifest(tp.bounds.hi)) + } else if(undetParams contains sym) { // looking for a manifest of a type parameter that hasn't been inferred by now, can't do much, but let's not fail + mot(NothingClass.tpe) // TODO: should we include the mapping from sym -> NothingClass.tpe in the SearchResult? (it'll get instantiated to nothing anyway, I think) } else { EmptyTree // a manifest should have been found by normal searchImplicit } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 381b1ceed3..6b8c2fe0b4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -804,15 +804,10 @@ trait Typers { self: Analyzer => context.undetparams = context.undetparams ::: tparams1 adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt, original) case mt: MethodType if mt.isImplicit && ((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) => // (4.1) - if (!context.undetparams.isEmpty/* && (mode & POLYmode) == 0 disabled to make implicits in new collection work; we should revisit this. */) { // (9) - // println("adapt IMT: "+(context.undetparams, pt)) //@MDEBUG - context.undetparams = inferExprInstance( - tree, context.extractUndetparams(), pt, mt.params exists (p => isManifest(p.tpe))) - // if we are looking for a manifest, instantiate type to Nothing anyway, - // as we would get amnbiguity errors otherwise. Example - // Looking for a manifest of Nil: This mas many potential types, - // so we need to instantiate to minimal type List[Nothing]. - } + if (context.undetparams nonEmpty) // (9) -- should revisit dropped condition `(mode & POLYmode) == 0` + // dropped so that type args of implicit method are inferred even if polymorphic expressions are allowed + // needed for implicits in 2.8 collection library -- maybe once #3346 is fixed, we can reinstate the condition? + context.undetparams = inferExprInstance(tree, context.extractUndetparams(), pt, false) // false: retract Nothing's that indicate failure, ambiguities in manifests are dealt with in manifestOfType val typer1 = constrTyperIf(treeInfo.isSelfOrSuperConstrCall(tree)) if (original != EmptyTree && pt != WildcardType) typer1.silent(tpr => tpr.typed(tpr.applyImplicitArgs(tree), mode, pt)) match { diff --git a/test/files/pos/nothing_manifest_disambig.scala b/test/files/pos/nothing_manifest_disambig.scala new file mode 100644 index 0000000000..9a3db0c6d4 --- /dev/null +++ b/test/files/pos/nothing_manifest_disambig.scala @@ -0,0 +1,10 @@ +object Test { + def mani[T: Manifest](xs: T) = xs + mani(List()) + + def listElMani[T: Manifest](xs: List[T]) = xs + listElMani(List()) + + def foo[A, C](m : C)(implicit ev: C <:< Traversable[A], mani: Manifest[A]): (C, A, Manifest[A]) = (m, m.head, mani) + foo(List(1,2,3)) +}
\ No newline at end of file |