From a5cd601dacb94d65ba035f5ca9fd3c2064668b70 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Mon, 24 Feb 2014 23:28:54 -0800 Subject: SI-8197 clarify overloading resolution with default args This commit was co-authored with Lukas. His analysis is below. If there are multiple applicable alternatives, drop those that use default arguments. This is done indirectly by checking applicability based on arity. TODO: this `namesMatch` business is not spec'ed, and is the wrong fix for SI-4592. We should instead clarify what the spec means by "typing each argument with an undefined expected type". What does typing a named argument entail when we don't know what the valid parameter names are? (Since we're doing overload resolution, there are multiple alternatives that can define different names.) Luckily, the next step checks applicability to the individual alternatives, so it knows whether an assignment is: - a valid named argument - a well-typed assignment (which doesn't necessarily have type `Unit`!) - an error (e.g., rhs does not refer to a variable) I propose the following solution (as a TODO): check whether a named argument (when typing it in `doTypedApply`) could be interpreted as an assign; `infer.checkNames` should use the type of the well-typed assignment instead of `Unit`. Lukas's analysis: 990fa04 misunderstood the spec of overloading resolution with defaults. it should not discard applicable alternatives that define defaults, but only those that use defaults in the given invocation. bugs were shadowed because the refactoring used `alt.hasDefault` to check whether the alternative has some parameters with defaults, but this never worked. d5bb19f fixed that part by checking the flags of parameters, which fixed some but but un-shadowed others: ``` object t { def f(x: String = "") = 1; def f(x: Object) = 2 } scala> t.f("") // should return 1, but returns 2 after d5bb19f ``` The commit message of d5bb19f also mentions that its test "should fail to compile according to SI-4728", which is another misunderstanding. ``` class A; class B extends A object t { def f(x: A = null) = 1; def f(x: B*) = 2 } t.f() ``` This should return `2`: both alternatives are applicable, so the one that uses a default is eliminated, and we're left with the vararg one. SI-4728 is different in that it uses explicit parameters, `t.f(new B)` is ambiguous. --- test/files/run/t8197.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/files/run/t8197.scala b/test/files/run/t8197.scala index 5ca67088de..910a3ebc83 100644 --- a/test/files/run/t8197.scala +++ b/test/files/run/t8197.scala @@ -1,7 +1,7 @@ -// NOTE: according to SI-4728, this shouldn't even compile... +// SI-8197, see also SI-4592 and SI-4728 class A class B -// default arguments do not participate in overload resolution + class Foo(val x: A = null) { def this(bla: B*) { this(new A) @@ -9,5 +9,8 @@ class Foo(val x: A = null) { } object Test extends App { + // both constructors of `Foo` are applicable. Overloading resolution + // will eliminate the alternative that uses a default argument, therefore + // the vararg constructor is chosen. assert((new Foo).x != null) } -- cgit v1.2.3