diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2014-02-24 23:28:54 -0800 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2014-02-25 11:08:35 -0800 |
commit | a5cd601dacb94d65ba035f5ca9fd3c2064668b70 (patch) | |
tree | dc796e5736af08ad5d8c3a158b7405a8b2c57bdf /src/compiler/scala/tools/nsc/typechecker/Typers.scala | |
parent | 7c709e122f7471353749525cff15602783fb348c (diff) | |
download | scala-a5cd601dacb94d65ba035f5ca9fd3c2064668b70.tar.gz scala-a5cd601dacb94d65ba035f5ca9fd3c2064668b70.tar.bz2 scala-a5cd601dacb94d65ba035f5ca9fd3c2064668b70.zip |
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.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 8a3ceb3aca..153e32f3a3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3214,10 +3214,23 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper args.map { case arg @ AssignOrNamedArg(Ident(name), rhs) => // named args: only type the righthand sides ("unknown identifier" errors otherwise) - val rhs1 = typedArg0(rhs) // the assign is untyped; that's ok because we call doTypedApply - val arg1 = treeCopy.AssignOrNamedArg(arg, arg.lhs, rhs1) - (arg1, NamedType(name, rhs1.tpe.deconst)) + val typedRhs = typedArg0(rhs) + val argWithTypedRhs = treeCopy.AssignOrNamedArg(arg, arg.lhs, typedRhs) + + // TODO: SI-8197/SI-4592: check whether this named argument could be interpreted as an assign + // infer.checkNames must not use UnitType: it may not be a valid assignment, or the setter may return another type from Unit + // + // var typedAsAssign = true + // val argTyped = silent(_.typedArg(argWithTypedRhs, amode, BYVALmode, WildcardType)) orElse { errors => + // typedAsAssign = false + // argWithTypedRhs + // } + // + // TODO: add an assignmentType field to NamedType, equal to: + // assignmentType = if (typedAsAssign) argTyped.tpe else NoType + + (argWithTypedRhs, NamedType(name, typedRhs.tpe.deconst)) case arg @ treeInfo.WildcardStarArg(repeated) => val arg1 = typedArg0(arg) (arg1, RepeatedType(arg1.tpe.deconst)) |