Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 483146 - [null] Odd behavior passing @NonNull to unconstrained parameter
Summary: [null] Odd behavior passing @NonNull to unconstrained parameter
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.6   Edit
Hardware: PC Windows 10
: P3 normal (vote)
Target Milestone: 4.6 M4   Edit
Assignee: Stephan Herrmann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-11-27 02:06 EST by Marc-André Laperle CLA
Modified: 2015-12-08 08:55 EST (History)
4 users (show)

See Also:


Attachments
Example project (3.95 KB, application/zip)
2015-11-27 02:06 EST, Marc-André Laperle CLA
no flags Details
Example project (3.95 KB, application/zip)
2015-11-27 02:07 EST, Marc-André Laperle CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Marc-André Laperle CLA 2015-11-27 02:06:07 EST
Using 4.6-I20151124-1000

I am seeing errors when passing @NonNull to unconstrained parameter. The parameter is generic, so that might have something to do with it.

Here is the snippet:

void example1() {
	@Nullable
	List<String> container = new ArrayList<>();
	@NonNull List<String> list = checkNotNull(container);
}

void example2() {
	@NonNull
	List<String> container= new ArrayList<>();
	@NonNull List<String> list = checkNotNull(container); // Null constraint mismatch: The type '@NonNull List<String>' is not a valid substitute for the type parameter 'C extends Iterable<T>'
}

@NonNull <T, C extends Iterable<T>> C checkNotNull(C container) {
	if (container == null) {
		throw new NullPointerException();
	}
	return container;
}

Here is my understanding of this:
In the checkNotNull method signature, the C in the parameter and T are unconstrained. Only the C returned is constrained. 
In example1, the List is @Nullable and the <String> is unconstrained, which is compatible with the unconstrained C and T in checkNotNull.
In example2, the List is @NonNull and the <String> is unconstrained, which (I thought!) should be compatible with the unconstrained C and T in checkNotNull. But this gives an error.

If I change checkNotNull's parameter to @Nullable C container, example2 works but not example1.
Comment 1 Marc-André Laperle CLA 2015-11-27 02:06:58 EST
Created attachment 258301 [details]
Example project
Comment 2 Marc-André Laperle CLA 2015-11-27 02:07:30 EST
Created attachment 258302 [details]
Example project
Comment 3 Stephan Herrmann CLA 2015-11-27 14:15:47 EST
Thanks, I can reproduce.

It seems the error is only flagged when the invocation to checkNonNull is redundant. Strange.
Comment 4 Stephan Herrmann CLA 2015-11-27 15:14:58 EST
The bug is in null-aware type inference:

We have these TypeBounds:

  T#0 = java.lang.String
  @NonNull C#1 <: java.util.List<java.lang.String>

from which we derive this constraint:

  ⟨@NonNull C#1 <: java.util.List<java.lang.String>⟩

seeing the @NonNull we wrongly add it to the nullHints of both input TypeBounds.

This can be fixed by performing this transfer (needed for Bug 428985) only when combination of TypeBounds is based on a direct substitution of equal LHS ivars (like  T#0 <: Foo  &  T#0 >: Goo  =>  Goo <: Foo).


Additionally, the derivation of the above constraint can be avoided altogether; We are applying this rule:
  α = U and S <: T imply ⟨S[α:=U] <: T[α:=U]⟩
If neither substitution in the consequent has any effect, then the resulting new constraint is always equivalent to the second input bound, so let's just avoid creating and incorporating it (again).
Comment 5 Eclipse Genie CLA 2015-11-27 15:16:34 EST
New Gerrit change created: https://git.eclipse.org/r/61498
Comment 7 Manoj N Palat CLA 2015-12-08 08:55:48 EST
Verified for Eclipse Neon Version: Neon 4.6M4 Build id: I20151207-0800