Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 455549

Summary: Wildcard 'Type mismatch'
Product: [Eclipse Project] JDT Reporter: Chris Hubick <chris>
Component: CoreAssignee: Stephan Herrmann <stephan.herrmann>
Status: CLOSED WONTFIX QA Contact:
Severity: normal    
Priority: P3 CC: jarthana, stephan.herrmann
Version: 4.5   
Target Milestone: 4.15 M3   
Hardware: PC   
OS: Linux   
Whiteboard: stalebug

Description Chris Hubick CLA 2014-12-17 19:28:05 EST
> import java.util.*;
> import java.util.function.*;
> import java.util.stream.*;
> 
> public class Test {
> 
>   public abstract static class TreeNode<ChildT extends TreeNode<?>> {
>     public abstract Optional<ChildT> getChild(String id);
>   }
> 
>   public abstract static class TextNode<ChildT extends TextNode<?>> extends TreeNode<ChildT> {}
> 
>   public abstract static class Document extends TreeNode<TextNode<?>> {}
> 
>   public static final Optional<TextNode<?>> getChildByID(List<Document> docs, String id) {
>     return docs.stream().map((root) -> root.getChild(id)).filter(Optional::isPresent).map(Optional::get).findAny(); // ERROR: Type mismatch: cannot convert from Optional<Test.TextNode<capture#1-of ?>> to Optional<Test.TextNode<?>>
>   }
> 
> }

eclipse.buildId=4.5.0.I20141216-0800
java.version=1.8.0_25

Compiles fine with javac.
Comment 1 Jay Arthanareeswaran CLA 2014-12-18 02:40:38 EST
Reproducible on master, looks likes a regression after bug 437444 was fixed.

Sasi, please take it forward.
Comment 2 Sasikanth Bharadwaj CLA 2015-01-08 00:35:29 EST
This can be traced to this change in CEF.reduceReferenceExpressionCompatibility
-			TypeBinding rPrime = compileTimeDecl.isConstructor() ? compileTimeDecl.declaringClass : compileTimeDecl.returnType;
+			TypeBinding rPrime = compileTimeDecl.isConstructor() ? compileTimeDecl.declaringClass : 																								compileTimeDecl.returnType.capture(inferenceContext.scope, reference.sourceEnd());

Removing the capture solves the issue. And it does not impact any java8 tests.Trying to find an explanation for why this was required and why it isn't needed any more
Comment 3 Stephan Herrmann CLA 2015-01-08 06:12:53 EST
(In reply to Sasikanth Bharadwaj from comment #2)
> This can be traced to this change in
> CEF.reduceReferenceExpressionCompatibility
> -			TypeBinding rPrime = compileTimeDecl.isConstructor() ?
> compileTimeDecl.declaringClass : compileTimeDecl.returnType;
> +			TypeBinding rPrime = compileTimeDecl.isConstructor() ?
> compileTimeDecl.declaringClass : 																							
> compileTimeDecl.returnType.capture(inferenceContext.scope,
> reference.sourceEnd());
> 
> Removing the capture solves the issue. And it does not impact any java8
> tests.Trying to find an explanation for why this was required and why it
> isn't needed any more

From a SPEC we should *always* apply capture here (i.e., also to compileTypeDecl.declaringClass). We're looking at the last bullet in 18.2.1:
  "let R' be the result of applying capture conversion (§5.1.10) to the return type of the invocation type (§15.12.2.6) of the compile-time declaration"

Not doing so before bug 437444 was on oversight on my behalf.

Unless this is being changed by one of the JDK bugs referenced in bug 437444, we should not lightly remove capturing.
Comment 4 Sasikanth Bharadwaj CLA 2015-01-23 03:33:35 EST
(In reply to comment #3)
> 
> From a SPEC we should *always* apply capture here (i.e., also to
> compileTypeDecl.declaringClass). We're looking at the last bullet in 18.2.1:
> "let R' be the result of applying capture conversion (§5.1.10) to the return
> type of the invocation type (§15.12.2.6) of the compile-time declaration"
> 
> Not doing so before bug 437444 was on oversight on my behalf.
> 
> Unless this is being changed by one of the JDK bugs referenced in bug 437444, we
> should not lightly remove capturing.
Thanks Stephan for the pointer. This leads me to believe that we are doing the right thing here. Replacing the method reference Optional::get with the lambda (o) -> {return o.get();} causes javac to complain as well. 
Breaking up the statement into two like

Stream<TextNode<?>> s = docs.stream().map((root) -> root.getChild(id)).filter(Optional::isPresent).map(Optional::get);
	return s.findAny();
	
is accepted but in a single statement, the capture would be present in the type of the invocation and hence the return type will be incompatible with the declared type
I'm still looking in the spec to find something that would dictate the behavior to be different. Stephan, another push in the right direction please...
Comment 5 Chris Hubick CLA 2015-01-23 11:17:25 EST
Providing an explicit type to Stream.map() also seems to be accepted:

> return docs.stream().map((root) -> root.getChild(id)).filter(Optional::isPresent).<TextNode<?>> map(Optional::get).findAny();
Comment 6 Eclipse Genie CLA 2020-02-03 13:05:11 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. As such, we're closing this bug.

If you have further information on the current state of the bug, please add it and reopen this bug. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 7 Stephan Herrmann CLA 2020-02-04 08:57:15 EST
The most closely related spec bug is https://bugs.openjdk.java.net/browse/JDK-8054721 which has not produced a solution in over 5 years. Ergo we will do the same: nothing.