summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-10-07 14:10:34 +0000
committerMartin Odersky <odersky@gmail.com>2009-10-07 14:10:34 +0000
commit9f121f57e034a7feb07bad7f67403f3ac75b46d4 (patch)
treedd68aed8983422a39dbc867397762a7bc5e5a9f8 /src/compiler/scala/tools/nsc/typechecker/Implicits.scala
parentad62d9f8b00d328c099268366ae05c5122915fa6 (diff)
downloadscala-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.scala103
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`.