Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
More precise prototype for args of overloaded method
Normally, overload resolution types the arguments to the alternatives without an expected type. However, typing function literals and eta-expansion are driven by the expected type: - function literals usually don't have parameter types, which are derived from the expected type; - eta-expansion right now only happens when a function/sam type is expected. (Dotty side-steps these issues by eta-expanding regardless of expected type.) Now that the collections are full of overloaded HO methods, we should try harder to type check them nicely. To avoid breaking existing code, we only provide an expected type (for each argument position) when: - there is at least one FunctionN type expected by one of the overloads: in this case, the expected type is a FunctionN[Ti, ?], where Ti are the argument types (they must all be =:=), and the expected result type is elided using a wildcard. This does not exclude any overloads that expect a SAM, because they conform to a function type through SAM conversion - OR: all overloads expect a SAM type of the same class, but with potentially varying result types (argument types must be =:=) We allow polymorphic cases, as long as the types parameters are instantiated by the AntiPolyType prefix. In all other cases, the old behavior is maintained: Wildcard is expected. (Slightly) more formally: Consider an overloaded method `m_i`, with `N` overloads `i = 1..N`, and an expected argument type at index `j`, `a_ij`: ``` def m_1(... a_1j, ...) .. def m_N(... a_Nj, ...) ``` Any polymorphic method `m_i` will be reduced to the monomorphic case by pushing down the method's `PolyType` to its arguments `a_ij`. The expected type for the argument at index `j` will be more precise than the usual `WildcardType` (`?`), if all types `a_1j..a_Nj` are function-ish types that denote the same parameter types `p1..pM`. A "function-ish" type is a `FunctionN[p1,...,pM]` (or `PartialFunction`), or the equivalent SAM type. (We first unwrap any PolyTypes.) The non-wildcard expected type will be - `PartialFunction[p1, ?]`, if an `a_ij` expects a partial function; - else, if there is a subclass of `FunctionM` among the `a_ij`, it is `FunctionM[p1, pM, ?]`; - else, if all `a_ij` are of the same SAM type (allowing for varying result types), that SAM type (with `?` result type). In each case, any type parameter not already resolved by overloading, or the outer context, it approximated by `?`. PS: type equivalence is decided as `tp1 <:< tp2 && tp2 <:< tp1`, and not `tp1 =:= tp2` (the latter is actually stricter).
- Loading branch information
Showing
9 changed files
with
314 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,4 @@ | ||
t6214.scala:5: error: ambiguous reference to overloaded definition, | ||
both method m in object Test of type (f: Int => Unit)Int | ||
and method m in object Test of type (f: String => Unit)Int | ||
match argument types (Any => Unit) | ||
t6214.scala:5: error: missing parameter type | ||
m { s => case class Foo() } | ||
^ | ||
^ | ||
one error found |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
object Util { | ||
def mono(x: Int) = x | ||
def poly[T](x: T): T = x | ||
} | ||
|
||
trait FunSam[-T, +R] { def apply(x: T): R } | ||
|
||
|
||
trait TFun { def map[T](f: T => Int): Unit = () } | ||
object Fun extends TFun { import Util._ | ||
def map[T: scala.reflect.ClassTag](f: T => Int): Unit = () | ||
|
||
map(mono) | ||
map(mono _) | ||
map(x => mono(x)) | ||
|
||
// can't infer polymorphic type for function parameter: | ||
// map(poly) | ||
// map(poly _) | ||
// map(x => poly(x)) | ||
} | ||
|
||
trait TSam { def map[T](f: T FunSam Int): Unit = () } | ||
object Sam extends TSam { import Util._ | ||
def map[T: scala.reflect.ClassTag](f: T `FunSam` Int): Unit = () | ||
|
||
map(mono) // sam | ||
map(mono _) // sam | ||
map(x => mono(x)) // sam | ||
|
||
// can't infer polymorphic type for function parameter: | ||
// map(poly) | ||
// map(poly _) | ||
// map(x => poly(x)) | ||
} | ||
|
||
trait IntFun { def map[T](f: Int => T): Unit = () } | ||
object int_Fun extends IntFun { import Util._ | ||
def map[T: scala.reflect.ClassTag](f: Int => T): Unit = () | ||
|
||
map(mono) | ||
map(mono _) | ||
map(x => mono(x)) | ||
|
||
map(poly) | ||
map(poly _) | ||
map(x => poly(x)) | ||
} | ||
|
||
trait IntSam { def map[T](f: Int FunSam T): Unit = () } | ||
object int_Sam extends IntSam { import Util._ | ||
def map[T: scala.reflect.ClassTag](f: Int `FunSam` T): Unit = () | ||
|
||
map(mono) // sam | ||
map(mono _) // sam | ||
map(x => mono(x)) // sam | ||
|
||
map(poly) // sam | ||
map(poly _) // sam | ||
map(x => poly(x)) // sam | ||
} | ||
|
||
|
||
/* | ||
eta_overload_hof.scala:27: error: missing argument list for method mono in object Util | ||
Unapplied methods are only converted to functions when a function type is expected. | ||
You can make this conversion explicit by writing `mono _` or `mono(_)` instead of `mono`. | ||
map(mono) | ||
^ | ||
eta_overload_hof.scala:46: error: type mismatch; | ||
found : Nothing => Nothing | ||
required: ?<: Int => ? | ||
map(poly _) | ||
^ | ||
eta_overload_hof.scala:54: error: missing argument list for method mono in object Util | ||
Unapplied methods are only converted to functions when a function type is expected. | ||
You can make this conversion explicit by writing `mono _` or `mono(_)` instead of `mono`. | ||
map(mono) | ||
^ | ||
eta_overload_hof.scala:58: error: missing argument list for method poly in object Util | ||
Unapplied methods are only converted to functions when a function type is expected. | ||
You can make this conversion explicit by writing `poly _` or `poly(_)` instead of `poly`. | ||
map(poly) | ||
^ | ||
eta_overload_hof.scala:59: error: overloaded method value map with alternatives: | ||
[T](f: FunSam[Int,T])(implicit evidence$4: scala.reflect.ClassTag[T])Unit <and> | ||
[T](f: FunSam[Int,T])Unit | ||
cannot be applied to (Nothing => Nothing) | ||
map(poly _) | ||
^ | ||
eta_overload_hof.scala:60: error: missing parameter type | ||
map(x => poly(x)) | ||
^ | ||
* */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// TODO make independent of java.io.OutputStream, but obvious way does not capture the bug (see didInferSamType and OverloadedArgFunProto) | ||
class Test { | ||
def overloadedAccidentalSam(a: java.io.OutputStream, b: String) = ??? | ||
def overloadedAccidentalSam(a: java.io.OutputStream, b: Any)= ??? | ||
|
||
overloadedAccidentalSam(??? : java.io.OutputStream, null) | ||
} |
Oops, something went wrong.