diff options
author | Martin Odersky <odersky@gmail.com> | 2009-10-07 14:10:34 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2009-10-07 14:10:34 +0000 |
commit | 9f121f57e034a7feb07bad7f67403f3ac75b46d4 (patch) | |
tree | dd68aed8983422a39dbc867397762a7bc5e5a9f8 /src/compiler/scala/tools/nsc/typechecker/Implicits.scala | |
parent | ad62d9f8b00d328c099268366ae05c5122915fa6 (diff) | |
download | scala-9f121f57e034a7feb07bad7f67403f3ac75b46d4.tar.gz scala-9f121f57e034a7feb07bad7f67403f3ac75b46d4.tar.bz2 scala-9f121f57e034a7feb07bad7f67403f3ac75b46d4.zip |
Fixed #1000, #2060
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Implicits.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Implicits.scala | 103 |
1 files changed, 82 insertions, 21 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index d2498741f3..e9ca2dd7c5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -27,7 +27,7 @@ self: Analyzer => import global._ import definitions._ - final val traceImplicits = false + def traceImplicits = printTypings var implicitTime = 0L var inscopeSucceed = 0L @@ -121,6 +121,59 @@ self: Analyzer => /** A sentinel indicating no implicit was found */ val NoImplicitInfo = new ImplicitInfo(null, NoType, NoSymbol) + /** A constructor for types ?{ name: tp }, used in infer view to member + * searches. + */ + def memberWildcardType(name: Name, tp: Type) = { + val result = refinedType(List(WildcardType), NoSymbol) + var psym = if (name.isTypeName) result.typeSymbol.newAbstractType(NoPosition, name) + else result.typeSymbol.newValue(NoPosition, name) + psym setInfo tp + result.decls enter psym + result + } + + /** An extractor for types of the form ? { name: ? } + */ + object HasMember { + def apply(name: Name): Type = memberWildcardType(name, WildcardType) + def unapply(pt: Type): Option[Name] = pt match { + case RefinedType(List(WildcardType), decls) => + decls.toList match { + case List(sym) if (sym.tpe == WildcardType) => Some(sym.name) + case _ => None + } + case _ => + None + } + } + + /** An extractor for types of the form ? { name: (? >: argtpe <: Any*)restp } + */ + object HasMethodMatching { + def apply(name: Name, argtpes: List[Type], restpe: Type): Type = { + def templateArgType(argtpe: Type) = + new BoundedWildcardType(mkTypeBounds(argtpe, AnyClass.tpe)) + val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "typer$dummy") + val mtpe = MethodType(dummyMethod.newSyntheticValueParams(argtpes map templateArgType), restpe) + memberWildcardType(name, mtpe) + } + def unapply(pt: Type): Option[(Name, List[Type], Type)] = pt match { + case RefinedType(List(WildcardType), decls) => + decls.toList match { + case List(sym) => + sym.tpe match { + case MethodType(params, restpe) + if (params forall (_.tpe.isInstanceOf[BoundedWildcardType])) => + Some((sym.name, params map (_.tpe.bounds.lo), restpe)) + case _ => None + } + case _ => None + } + case _ => None + } + } + /** A class that sets up an implicit search. For more info, see comments for `inferImplicit`. * @param tree The tree for which the implicit needs to be inserted. * @param pt The original expected type of the implicit. @@ -291,16 +344,38 @@ self: Analyzer => */ val wildPt = approximate(pt) - //if (traceImplicits) println("typed impl for "+wildPt+"? "+info.name+":"+info.tpe+"/"+undetParams) - if (isPlausiblyCompatible(info.tpe, wildPt) && - isCompatible(depoly(info.tpe), wildPt) && - isStable(info.pre)) { + /** Does type `tp' match wildPt? + * This is the case if either `wildPt' is a HasMethodMatching type + * and `tp' has a method matching wildPt, or otherwise if + * `tp' stripped of universal quantifiers is compatible with `wildPt'. + */ + def matchesWildPt(tp: Type) = wildPt match { + case HasMethodMatching(name, argtpes, restpe) => + (tp.member(name) filter (m => isApplicableSafe(List(), m.tpe, argtpes, restpe))) != NoSymbol + case _ => + isCompatible(depoly(tp), wildPt) + } + + /** Does type `tp' match prototype `pt'? + * This is the case if either `pt' is a HasMethodMatching type + * and `tp' has a member matching `pt', or otherwise if + * `tp' is compatible with `pt'. + */ + def matchesPt(tp: Type, pt: Type) = pt match { + case HasMethodMatching(name, argtpes, restpe) => + (tp.member(name) filter (m => isApplicableSafe(undetParams, m.tpe, argtpes, restpe))) != NoSymbol + case _ => + isCompatible(tp, pt) + } + + if (traceImplicits) println("typed impl for "+wildPt+"? "+info.name+":"+depoly(info.tpe)+"/"+undetParams+"/"+isPlausiblyCompatible(info.tpe, wildPt)+"/"+matchesWildPt(info.tpe)) + if (isPlausiblyCompatible(info.tpe, wildPt) && matchesWildPt(info.tpe) && isStable(info.pre)) { val itree = atPos(tree.pos.focus) { 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 "+wildPt) + if (traceImplicits) println("typed impl?? "+info.name+":"+info.tpe+" ==> "+itree+" with pt = "+pt+", wildpt = "+wildPt) def fail(reason: String): SearchResult = { if (settings.XlogImplicits.value) inform(itree+" is not a valid implicit value for "+pt+" because:\n"+reason) @@ -333,7 +408,7 @@ self: Analyzer => if (itree2.tpe.isError) SearchFailure else if (hasMatchingSymbol(itree1)) { val tvars = undetParams map freshVar - if (isCompatible(itree2.tpe, pt.instantiateTypeParams(undetParams, tvars))) { + if (matchesPt(itree2.tpe, pt.instantiateTypeParams(undetParams, tvars))) { if (traceImplicits) println("tvars = "+tvars+"/"+(tvars map (_.constr))) val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt), false, lubDepth(List(itree2.tpe, pt))) @@ -670,20 +745,6 @@ self: Analyzer => mot(tp) } - /** An extractor for types of the form ? { name: ? } - */ - object WildcardName { - def unapply(pt: Type): Option[Name] = pt match { - case RefinedType(List(WildcardType), decls) => - decls.toList match { - case List(sym) if (sym.tpe == WildcardType) => Some(sym.name) - case _ => None - } - case _ => - None - } - } - /** The result of the implicit search: * First search implicits visible in current context. * If that fails, search implicits in expected type `pt`. |