summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSom Snytt <som.snytt@gmail.com>2012-05-21 11:41:23 -0700
committerSom Snytt <som.snytt@gmail.com>2012-05-21 12:31:27 -0700
commitf6a4d945698bac9b64a2d2ddaf44eb7302336670 (patch)
tree746ddbb88e76085c95348bcb715490a6adb028ee /src
parentf406550146250f5a6036d3d778582efa6d68252a (diff)
downloadscala-f6a4d945698bac9b64a2d2ddaf44eb7302336670.tar.gz
scala-f6a4d945698bac9b64a2d2ddaf44eb7302336670.tar.bz2
scala-f6a4d945698bac9b64a2d2ddaf44eb7302336670.zip
SI-3761: Overload resolution fails on by-name parameter
When isAsSpecific checks if method m applies to args of types of formal params of m1, a by-name parameter was converted to its underlying result type for the params (of m) but not the args (of m1). This had the useful effect of making m(A) more specific than m(=>A), which is the specified prioritization for implicit views, but also made m(=>A) and m(=>A, B*) ambiguous. To handle this edge case, the isCompatible test for A and =>A is made explicit, and by-name params are no longer converted.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala21
1 files changed, 17 insertions, 4 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 1c1adee343..34b951a797 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -305,9 +305,21 @@ trait Infer {
}
- def isCompatible(tp: Type, pt: Type): Boolean = {
+ /** "Compatible" means conforming after conversions.
+ * "Raising to a thunk" is not implicit; therefore, for purposes of applicability and
+ * specificity, an arg type `A` is considered compatible with cbn formal parameter type `=>A`.
+ * For this behavior, the type `pt` must have cbn params preserved; for instance, `formalTypes(removeByName = false)`.
+ *
+ * `isAsSpecific` no longer prefers A by testing applicability to A for both m(A) and m(=>A)
+ * since that induces a tie between m(=>A) and m(=>A,B*) [SI-3761]
+ */
+ private def isCompatible(tp: Type, pt: Type): Boolean = {
+ def isCompatibleByName(tp: Type, pt: Type): Boolean = pt match {
+ case TypeRef(_, ByNameParamClass, List(res)) if !isByNameParamType(tp) => isCompatible(tp, res)
+ case _ => false
+ }
val tp1 = normalize(tp)
- (tp1 weak_<:< pt) || isCoercible(tp1, pt)
+ (tp1 weak_<:< pt) || isCoercible(tp1, pt) || isCompatibleByName(tp, pt)
}
def isCompatibleArgs(tps: List[Type], pts: List[Type]) =
(tps corresponds pts)(isCompatible)
@@ -662,7 +674,7 @@ trait Infer {
case ExistentialType(tparams, qtpe) =>
isApplicable(undetparams, qtpe, argtpes0, pt)
case MethodType(params, _) =>
- val formals = formalTypes(params map { _.tpe }, argtpes0.length)
+ val formals = formalTypes(params map { _.tpe }, argtpes0.length, removeByName = false)
def tryTupleApply: Boolean = {
// if 1 formal, 1 argtpe (a tuple), otherwise unmodified argtpes0
@@ -682,7 +694,8 @@ trait Infer {
isCompatibleArgs(argtpes, formals) && isWeaklyCompatible(restpe, pt)
} else {
try {
- val AdjustedTypeArgs.Undets(okparams, okargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, argtpes, pt)
+ val blackTie = formalTypes(params map { _.tpe }, argtpes0.length)
+ val AdjustedTypeArgs.Undets(okparams, okargs, leftUndet) = methTypeArgs(undetparams, blackTie, restpe, argtpes, pt)
// #2665: must use weak conformance, not regular one (follow the monomorphic case above)
(exprTypeArgs(leftUndet, restpe.instantiateTypeParams(okparams, okargs), pt, useWeaklyCompatible = true)._1 ne null) &&
isWithinBounds(NoPrefix, NoSymbol, okparams, okargs)