This answer from JDK Developers themselves sort of covers the same area. Just notice that Stuart Marks says : "It might be possible for the compiler to be enhanced to cover this case in a future release". Though the case there is around lambdas
, this is not very different than you have. It's just the way compiler (at the moment) works. And we are "stuck" with this.
You can sort of look under the resolution of how a compiler thinks about return Stream.of("a").distinct();
and decides what type to use, via:
javac --debug=verboseResolution=all
which in an un-documented flag. If you compile with that flag, you will see some big output:
with actuals: no arguments
with type-args: no arguments
candidates:
#0 applicable method found: Object()
DeleteMe.java:60: Note: resolving method of in type Stream to candidate 1
return Stream.of("a").distinct();
^
phase: BASIC
with actuals: String
with type-args: no arguments
candidates:
#0 not applicable method found: <T#1>of(T#1...)
(cannot infer type-variable(s) T#1
(argument mismatch; String cannot be converted to T#1[]))
#1 applicable method found: <T#2>of(T#2)
(partially instantiated to: (String)Stream<String>)
where T#1,T#2 are type-variables:
T#1 extends Object declared in method <T#1>of(T#1...)
T#2 extends Object declared in method <T#2>of(T#2)
DeleteMe.java:60: Note: Deferred instantiation of method <T>of(T)
return Stream.of("a").distinct();
^
instantiated signature: (String)Stream<String>
target-type: <none>
where T is a type-variable:
T extends Object declared in method <T>of(T)
DeleteMe.java:60: Note: resolving method distinct in type Stream to candidate 0
return Stream.of("a").distinct();
^
phase: BASIC
with actuals: no arguments
with type-args: no arguments
candidates:
#0 applicable method found: distinct()
where T is a type-variable:
T extends Object declared in interface Stream
DeleteMe.java:60: error: incompatible types: Stream<String> cannot be converted to Stream<CharSequence>
return Stream.of("a").distinct();
^
1 error
I guess the most important part is this : (partially instantiated to: (String)Stream<String>)
You can see that the resolution of what type T
is, is done a method call basis; not of the whole chain of calls. If it would would, btw, this would complicate compilers works quite a lot. For a simple chain like this, things might look trivial, but it gets far, far more tricky and involved when there are many. Especially, when you find out about non-denotable types
, which will even further complicate this.