summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-09-28 11:09:14 +0000
committerMartin Odersky <odersky@gmail.com>2009-09-28 11:09:14 +0000
commit53d98e7d421d55054fb0bcb606539fc36364bebf (patch)
treebe6b68360458b97ab92a0dc3e963f365ae5acd95 /src
parent32cac0e3fde4a512d7322cd60146bdac7d1898d4 (diff)
downloadscala-53d98e7d421d55054fb0bcb606539fc36364bebf.tar.gz
scala-53d98e7d421d55054fb0bcb606539fc36364bebf.tar.bz2
scala-53d98e7d421d55054fb0bcb606539fc36364bebf.zip
refined implicit resolution.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala28
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala41
4 files changed, 57 insertions, 25 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index e447921beb..769174aead 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -609,7 +609,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
* @param pt ...
* @return the adapted tree
*/
- override protected def adapt(tree: Tree, mode: Int, pt: Type): Tree =
+ override protected def adapt(tree: Tree, mode: Int, pt: Type, original: Tree = EmptyTree): Tree =
adaptToType(tree, pt)
/** A replacement for the standard typer's `typed1' method */
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index f03b7d5096..12711a36c6 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -410,17 +410,22 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
}
}
+ val lastElemType = lastFormal.typeArgs.head
var suffix: Tree =
if (!args.isEmpty && (treeInfo isWildcardStarArg args.last)) {
val Typed(tree, _) = args.last;
- if (isJava && !(tree.tpe.typeSymbol == ArrayClass) && (tree.tpe.typeSymbol isSubClass TraversableClass)) sequenceToArray(tree)
- else tree
+ if (isJava)
+ if (tree.tpe.typeSymbol == ArrayClass) tree
+ else sequenceToArray(tree)
+ else
+ if (tree.tpe.typeSymbol isSubClass TraversableClass) tree
+ else arrayToSequence(tree, lastElemType)
} else {
- val lastElemType = lastFormal.typeArgs.head
val tree = mkArrayValue(args drop (formals.length - 1), lastElemType)
if (isJava || inPattern) tree
else arrayToSequence(tree, lastElemType)
}
+
atPhase(phase.next) {
if (isJava &&
suffix.tpe.typeSymbol == ArrayClass &&
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 737af2d36e..d8f54760a1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -451,6 +451,19 @@ trait Infer {
tp.isInstanceOf[MethodType] && // can perform implicit () instantiation
tp.paramTypes.length == 0 && isCompatible(tp.resultType, pt)
+ /** Like weakly compatible but don't apply any implicit conversions yet.
+ * Used when comparing the result type of a method with its prototype.
+ */
+ def isConservativelyCompatible(tp: Type, pt: Type): Boolean = {
+ val savedImplicitsEnabled = context.implicitsEnabled
+ context.implicitsEnabled = false
+ try {
+ isWeaklyCompatible(tp, pt)
+ } finally {
+ context.implicitsEnabled = savedImplicitsEnabled
+ }
+ }
+
def isCoercible(tp: Type, pt: Type): Boolean = false
def isCompatible(tps: List[Type], pts: List[Type]): Boolean =
@@ -556,7 +569,7 @@ trait Infer {
case ex: NoInstance => WildcardType
}
val tvars = tparams map freshVar
- if (isWeaklyCompatible(restpe.instantiateTypeParams(tparams, tvars), pt))
+ if (isConservativelyCompatible(restpe.instantiateTypeParams(tparams, tvars), pt))
List.map2(tparams, tvars) ((tparam, tvar) =>
instantiateToBound(tvar, varianceInTypes(formals)(tparam)))
else
@@ -611,7 +624,7 @@ trait Infer {
}
// check first whether type variables can be fully defined from
// expected result type.
- if (!isWeaklyCompatible(restpe.instantiateTypeParams(tparams, tvars), pt)) {
+ if (!isConservativelyCompatible(restpe.instantiateTypeParams(tparams, tvars), pt)) {
// 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
@@ -821,9 +834,13 @@ trait Infer {
case OverloadedType(pre, alts) =>
alts exists (alt => isAsSpecific(pre.memberType(alt), ftpe2))
case et: ExistentialType =>
- et.withTypeVars(isAsSpecific(_, ftpe2)) // !!! why isStrictly?
+ et.withTypeVars(isAsSpecific(_, ftpe2))
+ case mt: ImplicitMethodType =>
+ isAsSpecific(ftpe1.resultType, ftpe2)
case MethodType(params @ (x :: xs), _) =>
isApplicable(List(), ftpe2, params map (_.tpe), WildcardType)
+ case PolyType(tparams, mt: ImplicitMethodType) =>
+ isAsSpecific(PolyType(tparams, mt.resultType), ftpe2)
case PolyType(_, MethodType(params @ (x :: xs), _)) =>
isApplicable(List(), ftpe2, params map (_.tpe), WildcardType)
case ErrorType =>
@@ -834,12 +851,17 @@ trait Infer {
alts forall (alt => isAsSpecific(ftpe1, pre.memberType(alt)))
case et: ExistentialType =>
et.withTypeVars(isAsSpecific(ftpe1, _))
+ case mt: ImplicitMethodType =>
+ isAsSpecific(ftpe1, mt.resultType)
+ case PolyType(tparams, mt: ImplicitMethodType) =>
+ isAsSpecific(ftpe1, PolyType(tparams, mt.resultType))
case MethodType(_, _) | PolyType(_, MethodType(_, _)) =>
true
case _ =>
isAsSpecificValueType(ftpe1, ftpe2, List(), List())
}
}
+
/*
def isStrictlyMoreSpecific(ftpe1: Type, ftpe2: Type): Boolean =
ftpe1.isError || isAsSpecific(ftpe1, ftpe2) &&
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 1943fcc1a4..d9d9bda13f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -238,13 +238,12 @@ trait Typers { self: Analyzer =>
psym = to.decls enter psym
psym setInfo tp
try {
- inferView(tree, from, to, true)
+ inferView(tree, from, to, true)
} catch {
case ex: AssertionError =>
- println("infer view "+tree+" "+name+" "+context.undetparams)
+ println("inverView "+tree+", from = "+from+", name = "+name+" tp = "+tp)
throw ex
}
-
}
import infer._
@@ -762,25 +761,25 @@ trait Typers { self: Analyzer =>
* (13) When in mode EXPRmode, apply a view
* If all this fails, error
*/
- protected def adapt(tree: Tree, mode: Int, pt: Type): Tree = tree.tpe match {
+ protected def adapt(tree: Tree, mode: Int, pt: Type, original: Tree = EmptyTree): Tree = tree.tpe match {
case atp @ AnnotatedType(_, _, _) if canAdaptAnnotations(tree, mode, pt) => // (-1)
adaptAnnotations(tree, mode, pt)
case ct @ ConstantType(value) if ((mode & (TYPEmode | FUNmode)) == 0 && (ct <:< pt) && !onlyPresentation) => // (0)
treeCopy.Literal(tree, value)
case OverloadedType(pre, alts) if ((mode & FUNmode) == 0) => // (1)
inferExprAlternative(tree, pt)
- adapt(tree, mode, pt)
+ adapt(tree, mode, pt, original)
case PolyType(List(), restpe) => // (2)
- adapt(tree setType restpe, mode, pt)
+ adapt(tree setType restpe, mode, pt, original)
case TypeRef(_, sym, List(arg))
if ((mode & EXPRmode) != 0 && sym == ByNameParamClass) => // (2)
- adapt(tree setType arg, mode, pt)
+ adapt(tree setType arg, mode, pt, original)
case tr @ TypeRef(_, sym, _)
if sym.isAliasType && tr.normalize.isInstanceOf[ExistentialType] &&
((mode & (EXPRmode | LHSmode)) == EXPRmode) =>
- adapt(tree setType tr.normalize.skolemizeExistential(context.owner, tree), mode, pt)
+ adapt(tree setType tr.normalize.skolemizeExistential(context.owner, tree), mode, pt, original)
case et @ ExistentialType(_, _) if ((mode & (EXPRmode | LHSmode)) == EXPRmode) =>
- adapt(tree setType et.skolemizeExistential(context.owner, tree), mode, pt)
+ adapt(tree setType et.skolemizeExistential(context.owner, tree), mode, pt, original)
case PolyType(tparams, restpe) if ((mode & (TAPPmode | PATTERNmode | HKmode)) == 0) => // (3)
// assert((mode & HKmode) == 0) //@M a PolyType in HKmode represents an anonymous type function,
// we're in HKmode since a higher-kinded type is expected --> hence, don't implicitly apply it to type params!
@@ -794,7 +793,7 @@ trait Typers { self: Analyzer =>
else TypeApply(tree, tparams1 map (tparam =>
TypeTree(tparam.tpe) setPos tree.pos.focus)) setPos tree.pos
context.undetparams = context.undetparams ::: tparams1
- adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt)
+ adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt, original)
case mt: ImplicitMethodType if ((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)
context.undetparams = inferExprInstance(
@@ -805,7 +804,17 @@ trait Typers { self: Analyzer =>
// so we need to instantiate to minimal type List[Nothing].
}
val typer1 = constrTyperIf(treeInfo.isSelfOrSuperConstrCall(tree))
- typer1.typed(typer1.applyImplicitArgs(tree), mode, pt)
+ if (original != EmptyTree && pt != WildcardType)
+ typer1.silent(tpr => tpr.typed(tpr.applyImplicitArgs(tree), mode, pt)) match {
+ case result: Tree => result
+ case ex: TypeError =>
+ if (settings.debug.value) log("fallback on implicits: "+tree)
+ val tree1 = typed(original, mode, WildcardType)
+ tree1.tpe = addAnnotations(tree1, tree1.tpe)
+ if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, EmptyTree)
+ }
+ else
+ typer1.typed(typer1.applyImplicitArgs(tree), mode, pt)
case mt: MethodType
if (((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) &&
(context.undetparams.isEmpty || (mode & POLYmode) != 0)) =>
@@ -825,7 +834,7 @@ trait Typers { self: Analyzer =>
//println("eta "+tree+" ---> "+tree1+":"+tree1.tpe)
typed(tree1, mode, pt)
} else if (!meth.isConstructor && mt.params.isEmpty) { // (4.3)
- adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt)
+ adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt, original)
} else if (context.implicitsEnabled) {
errorTree(tree, "missing arguments for "+meth+meth.locationString+
(if (meth.isConstructor) ""
@@ -933,7 +942,7 @@ trait Typers { self: Analyzer =>
return tree
}
val tree1 = constfold(tree, pt) // (10) (11)
- if (tree1.tpe <:< pt) adapt(tree1, mode, pt)
+ if (tree1.tpe <:< pt) adapt(tree1, mode, pt, original)
else {
if ((mode & (EXPRmode | FUNmode)) == EXPRmode) {
pt.normalize match {
@@ -2966,10 +2975,6 @@ trait Typers { self: Analyzer =>
/** Try to apply function to arguments; if it does not work try to
* insert an implicit conversion.
- *
- * @param fun ...
- * @param args ...
- * @return ...
*/
def tryTypedApply(fun: Tree, args: List[Tree]): Tree = {
val start = System.nanoTime()
@@ -3775,7 +3780,7 @@ trait Typers { self: Analyzer =>
tree1.tpe = addAnnotations(tree1, tree1.tpe)
- val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt)
+ val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, tree)
if (printTypings) println("adapted "+tree1+":"+tree1.tpe.widen+" to "+pt+", "+context.undetparams); //DEBUG
// for (t <- tree1.tpe) assert(t != WildcardType)
// if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe)