diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 18 | ||||
-rw-r--r-- | test/files/run/t3761-overload-byname.check | 6 | ||||
-rw-r--r-- | test/files/run/t3761-overload-byname.scala | 23 |
3 files changed, 44 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 839cdee301..abe77ead9a 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 diff --git a/test/files/run/t3761-overload-byname.check b/test/files/run/t3761-overload-byname.check new file mode 100644 index 0000000000..3a0a273e64 --- /dev/null +++ b/test/files/run/t3761-overload-byname.check @@ -0,0 +1,6 @@ +hello! +hello working world +goodnight! +goodnight moon, nobody, noises everywhere +0 +1 diff --git a/test/files/run/t3761-overload-byname.scala b/test/files/run/t3761-overload-byname.scala new file mode 100644 index 0000000000..b1656c97ba --- /dev/null +++ b/test/files/run/t3761-overload-byname.scala @@ -0,0 +1,23 @@ + +class OverTheTop { + def info0(m: String) = m + "!" + def info0(m: String, args: Any*) = m +" "+ args.mkString(" ") + + // as reported + def info1(m: =>String) = m + "!" + def info1(m: =>String, args: Any*) = m +" "+ args.mkString(", ") + + // @lrytz + def m[A](x: => Int) = 0; def m[A](x: => Int, xs: Int*) = 1 +} +object Test { + def main(args: Array[String]) { + val top = new OverTheTop + println(top.info0("hello")) + println(top.info0("hello","working","world")) + println(top.info1("goodnight")) + println(top.info1("goodnight", "moon", "nobody", "noises everywhere")) + println(top.m(17)) + println(top.m(17,19)) + } +} |