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

Bug 416815

Summary: Compiler does not report type mismatch error when null is returned via ternary operator
Product: [Eclipse Project] JDT Reporter: Hansjoerg Haberlander <Hansjoerg.Haberlander>
Component: CoreAssignee: Stephan Herrmann <stephan.herrmann>
Status: VERIFIED INVALID QA Contact:
Severity: major    
Priority: P3 CC: daniel_megert, fbricon, jarthana, stephan.herrmann
Version: 3.1   
Target Milestone: 4.8 M6   
Hardware: All   
OS: All   
Whiteboard:

Description Hansjoerg Haberlander CLA 2013-09-09 02:45:37 EDT
Type mismatch error is not annotated in code when using the ternary operator:
public int noTypeMismatch() {
  return someBoolean ? null : 0; // no type mismatch error
}

Using regular if shows the annotation:
public int typeMismatch() {
   if (someBoolean) {
     return null; // type mismatch error
   } else {
     return 0;
   }
 }
Comment 1 Dani Megert CLA 2013-09-09 05:33:37 EDT
Broken since 1.5 was introduced.
Comment 2 Timo Kinnunen CLA 2013-09-09 07:00:29 EDT
I get a warning "Potential null pointer access: This expression of type Integer may be null but requires auto-unboxing", so this might be by design.
Comment 3 Dani Megert CLA 2013-09-09 07:14:26 EDT
(In reply to Timo Kinnunen from comment #2)
> I get a warning "Potential null pointer access: This expression of type
> Integer may be null but requires auto-unboxing", so this might be by design.

No, you don't out of the box.
Comment 4 Timo Kinnunen CLA 2013-09-09 07:40:37 EDT
That's true, I have almost every warning turned on. I didn't mean to imply that that warning would be emitted by default.
Comment 5 Stephan Herrmann CLA 2013-09-09 14:06:54 EDT
Note that ternary expressions have different typing rules than the otherwise equivalent if-then-else structure.

JLS 15.25 does allow various adaptations to make the 2nd and 3rd operands compatible, including boxing. So the compiler currently seems to infer the common type of "null" and "0" to be "Integer". In fact the resulting code should be fully functional :)

The warning "Potential null pointer access.." results from unboxing this Integer to yield the required int. But this happens *after* Integer has already been determined as the accepted type.

At a closer look, however, I read the JLS to only allow
 int & Integer -> Integer  (bullet 2)
 Integer & null -> Integer (bullet 3)
but not
 int & null

So, yes, we should report an error.
Comment 6 Fred Bricon CLA 2018-02-12 13:28:29 EST
Same issue reported through vscode-java (which uses jdt.ls, hence jdt, under the hood) https://github.com/redhat-developer/vscode-java/issues/436
Comment 7 Stephan Herrmann CLA 2018-02-12 17:17:12 EST
Some archeology:

When compiling the examples from comment 0 with javac, all versions complain about 'typeMismatch' and no version in [1.5,9] complains about 'noTypeMismatch'.

Not sure if this was the intended behavior all the time, but this well corresponds to what ecj is answering.

Checking the third guy in the game, JLS:

Up-to JLS7 we indeed see the bullet list cited in comment 5, which led me to conclude we should report an error.

Now for the big surprise, in JLS8 section 15.25 has been re-written to contain an explicit table of what's supported and what is not. In table 15.25-A [1] we do find a cell for 2nd operand null and 3rd operand int. Similarly in table 15.25-E for the inverse pair of int and null.

=> Ergo, JLS8 made legal what compilers have been accepting all along.

=> Ergo, nothing to fix.

[1] https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.25-400-A
Comment 8 Fred Bricon CLA 2018-02-12 17:26:53 EST
Regardless of what the spec says, that ternary expression is still potentially harmful,  and I think it deserves at least a warning, how else can we prevent users from doing stupid stuff?
Can something be done above the compiler layer?
Comment 9 Stephan Herrmann CLA 2018-02-12 17:42:08 EST
(In reply to Fred Bricon from comment #8)
> Regardless of what the spec says, that ternary expression is still
> potentially harmful,  and I think it deserves at least a warning, how else
> can we prevent users from doing stupid stuff?
> Can something be done above the compiler layer?

We already do, see comment 2.
(You have to enable that warning, though).
Comment 10 Fred Bricon CLA 2018-02-12 19:08:39 EST
The "potential null pointer access" is shown as per Hansjoerg' snippet

public int problemDetected() {
  return someBoolean ? null : 0;
}

but not if you don't return immediately:

public int noProblemDetected() {
  int i = someBoolean ? null : 0;//no warning/error
  return i;
}
Comment 11 Stephan Herrmann CLA 2018-02-12 19:37:27 EST
(In reply to Fred Bricon from comment #10)
> The "potential null pointer access" is shown as per Hansjoerg' snippet
> 
> public int problemDetected() {
>   return someBoolean ? null : 0;
> }
> 
> but not if you don't return immediately:
> 
> public int noProblemDetected() {
>   int i = someBoolean ? null : 0;//no warning/error
>   return i;
> }

Thanks, that looks like a bug to me. I filed bug 531073.
Comment 12 Jay Arthanareeswaran CLA 2018-03-06 10:14:06 EST
Verified for 4.8 M6