Bug 576026 - Internal compiler error: NPE: Cannot read field "id" because "local" is null
Summary: Internal compiler error: NPE: Cannot read field "id" because "local" is null
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.22   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: 4.22 M1   Edit
Assignee: Stephan Herrmann CLA
QA Contact:
URL:
Whiteboard:
Keywords: regression
: 576089 576095 576267 576269 576329 (view as bug list)
Depends on:
Blocks:
 
Reported: 2021-09-16 05:21 EDT by Ralf Leonhardt CLA
Modified: 2021-10-26 17:47 EDT (History)
12 users (show)

See Also:


Attachments
Folder Structure (103.74 KB, image/jpeg)
2021-09-16 06:38 EDT, Ralf Leonhardt CLA
no flags Details
.metadata/.log file (446.10 KB, text/plain)
2021-09-16 06:49 EDT, Ralf Leonhardt CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ralf Leonhardt CLA 2021-09-16 05:21:34 EDT
Hi,

After an attempt to upgrade from Java 16 to Java 17, and in the process attempting to upgrade from Eclipse 4.21 to Eclipse 4.22, a class that was previously working perfectly fine is now broken for no obvious reason and marked as containing an error ("little red "x") on line 0 (zero) according to the error log. The error is:

Internal compiler error: java.lang.NullPointerException: Cannot read field "id" because "local" is null at org.eclipse.jdt.internal.
 compiler.flow.UnconditionalFlowInfo.markAsDefinitelyNonNull(UnconditionalFlowInfo.java:1376)

Starting Eclipse with -clean did not solve the problem. Trying Project/Clean from the Eclipse menu did not solve the problem.

Starting a completely new, fresh workspace, re-generating the class from scratch, and then copy-pasting the code from the old, dysfunctional workspace, re-creates the same error in the new workspace.

Any idea how I can solve this? I am getting desperate ...
Comment 1 Andrey Loskutov CLA 2021-09-16 05:31:50 EDT
Could you please attach full error log here with the stack trace?
A small self containing java example that reproduces the problem would be great.
Comment 2 Ralf Leonhardt CLA 2021-09-16 05:47:13 EDT
Hi,

If I try Project/Clean, I get the error message "Problem Occurred: 'Building' has encountered a problem. Errors occurred during the built."

If I click on the "<< Details" button (is this the stack trace you need?), I see the following:

Errors occurred during the build.
Errors running builder 'Java Builder' on project 'ORFDatabase_v2.0'.
Cannot read field "id" because "local" is null

Unfortunately, I don't have a small self-containing java example, as the problem occurs with a large, pre-written class, which worked perfectly fine before the upgrade, but is now broken. The problem does not seem to affect all classes in the workspace.
Comment 3 Andrey Loskutov CLA 2021-09-16 06:19:11 EDT
(In reply to Ralf Leonhardt from comment #2)
> Hi,
> 
> If I try Project/Clean, I get the error message "Problem Occurred:
> 'Building' has encountered a problem. Errors occurred during the built."
> 
> If I click on the "<< Details" button (is this the stack trace you need?), I
> see the following:
> 
> Errors occurred during the build.
> Errors running builder 'Java Builder' on project 'ORFDatabase_v2.0'.
> Cannot read field "id" because "local" is null

Please go to the workspace location, and attach .metadata/.log file you will find there to this bug.
Comment 4 Ralf Leonhardt CLA 2021-09-16 06:38:39 EDT
Created attachment 287141 [details]
Folder Structure

My workspace folder is "Java - A Beginner's Guide". Shown is the content of this workspace folder. There is no ".metadata/.log" file.
Comment 5 Ralf Leonhardt CLA 2021-09-16 06:49:14 EDT
Created attachment 287142 [details]
.metadata/.log file

Found the .metadata/.log file (is attached).
Comment 6 Ralf Leonhardt CLA 2021-09-16 07:28:31 EDT
(In reply to Andrey Loskutov from comment #3)
> (In reply to Ralf Leonhardt from comment #2)
> > Hi,
> > 
> > If I try Project/Clean, I get the error message "Problem Occurred:
> > 'Building' has encountered a problem. Errors occurred during the built."
> > 
> > If I click on the "<< Details" button (is this the stack trace you need?), I
> > see the following:
> > 
> > Errors occurred during the build.
> > Errors running builder 'Java Builder' on project 'ORFDatabase_v2.0'.
> > Cannot read field "id" because "local" is null
> 
> Please go to the workspace location, and attach .metadata/.log file you will
> find there to this bug.

Sorry, I did not directly reply to your comment, but I attached the log file you requested as a new comment (above this one).
Comment 7 Andrey Loskutov CLA 2021-09-16 10:09:15 EDT
Thanks Ralf. 
Next time please don't convert plain text log file to rtf, it makes the log unreadable.

Here is the stack:

!ENTRY org.eclipse.jdt.core.manipulation 4 0 2021-09-16 11:37:44.984
!MESSAGE Error in JDT Core during AST creation
!STACK 0
java.lang.NullPointerException: Cannot read field "id" because "local" is null
	at org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo.markAsDefinitelyNonNull(UnconditionalFlowInfo.java:1376)
	at org.eclipse.jdt.internal.compiler.ast.SwitchStatement.analyseCode(SwitchStatement.java:195)
	at org.eclipse.jdt.internal.compiler.ast.SwitchExpression.analyseCode(SwitchExpression.java:685)
	at org.eclipse.jdt.internal.compiler.ast.LocalDeclaration.analyseCode(LocalDeclaration.java:97)
	at org.eclipse.jdt.internal.compiler.ast.MethodDeclaration.analyseCode(MethodDeclaration.java:129)
	at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.internalAnalyseCode(TypeDeclaration.java:959)
	at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.analyseCode(TypeDeclaration.java:304)
	at org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration.analyseCode(CompilationUnitDeclaration.java:136)
	at org.eclipse.jdt.core.dom.CompilationUnitResolver.resolve(CompilationUnitResolver.java:1243)
	at org.eclipse.jdt.core.dom.CompilationUnitResolver.resolve(CompilationUnitResolver.java:712)
	at org.eclipse.jdt.core.dom.ASTParser.internalCreateAST(ASTParser.java:1253)
	at org.eclipse.jdt.core.dom.ASTParser.createAST(ASTParser.java:868)
	at org.eclipse.jdt.core.manipulation.CoreASTProvider$1.run(CoreASTProvider.java:272)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.jdt.core.manipulation.CoreASTProvider.createAST(CoreASTProvider.java:264)
	at org.eclipse.jdt.core.manipulation.CoreASTProvider.getAST(CoreASTProvider.java:197)
	at org.eclipse.jdt.core.manipulation.SharedASTProviderCore.getAST(SharedASTProviderCore.java:138)
	at org.eclipse.jdt.ui.OverrideIndicatorLabelDecorator.getOverrideIndicators(OverrideIndicatorLabelDecorator.java:161)
	at org.eclipse.jdt.ui.OverrideIndicatorLabelDecorator.computeAdornmentFlags(OverrideIndicatorLabelDecorator.java:136)
	at org.eclipse.jdt.ui.OverrideIndicatorLabelDecorator.decorate(OverrideIndicatorLabelDecorator.java:263)
	at org.eclipse.ui.internal.decorators.LightweightDecoratorDefinition.decorate(LightweightDecoratorDefinition.java:251)
	at org.eclipse.ui.internal.decorators.LightweightDecoratorManager$LightweightRunnable.run(LightweightDecoratorManager.java:105)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.ui.internal.decorators.LightweightDecoratorManager.decorate(LightweightDecoratorManager.java:360)
	at org.eclipse.ui.internal.decorators.LightweightDecoratorManager.getDecorations(LightweightDecoratorManager.java:346)
	at org.eclipse.ui.internal.decorators.DecorationScheduler$1.ensureResultCached(DecorationScheduler.java:412)
	at org.eclipse.ui.internal.decorators.DecorationScheduler$1.run(DecorationScheduler.java:388)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)
Comment 8 Jay Arthanareeswaran CLA 2021-09-17 01:02:57 EDT
It's very difficult to get to the cause without a reproducible testcase. But something I noticed from your stack is that this occurs when analyzing a switch expression, which must be a fairly new addition to the code? With this, is there a way you can narrow down the code that causes this?
Comment 9 Stephan Herrmann CLA 2021-09-17 07:16:55 EDT
(In reply to Andrey Loskutov from comment #7)
> !ENTRY org.eclipse.jdt.core.manipulation 4 0 2021-09-16 11:37:44.984
> !MESSAGE Error in JDT Core during AST creation
> !STACK 0
> java.lang.NullPointerException: Cannot read field "id" because "local" is
> null
> 	at
> org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo.
> markAsDefinitelyNonNull(UnconditionalFlowInfo.java:1376)
> 	at
> org.eclipse.jdt.internal.compiler.ast.SwitchStatement.
> analyseCode(SwitchStatement.java:195)

I readily admit that it was my fault in bug 575609. All (?) other clients of localVariableBinding() do check for null, so null should be expected indeed.

Still seeing the code that triggers this would be very interesting, since reference.bits indicates we do have a local. Why then is the local binding null?
Comment 10 Igor Malinin CLA 2021-09-18 13:50:49 EDT
This is triggered on my project when upgrading to Java 17. See

https://github.com/test-full-band/tfb-video

After getting Java 17 update from marketplace the compiler failed with the NPE on this source:

https://github.com/test-full-band/tfb-video/blob/master/core/src/main/java/band/full/video/dolby/RpuDataNLQ.java

After commenting out switch expressions (with arrow syntax) the compiler error goes to next class with switch expressions. Old non-arrow style switches are working and not triggering the error.
Comment 11 Stephan Herrmann CLA 2021-09-18 17:51:07 EDT
(In reply to Igor Malinin from comment #10)
> This is triggered on my project when upgrading to Java 17. See
> 
> https://github.com/test-full-band/tfb-video
> 
> After getting Java 17 update from marketplace the compiler failed with the
> NPE on this source:
> 
> https://github.com/test-full-band/tfb-video/blob/master/core/src/main/java/
> band/full/video/dolby/RpuDataNLQ.java
> 
> After commenting out switch expressions (with arrow syntax) the compiler
> error goes to next class with switch expressions. Old non-arrow style
> switches are working and not triggering the error.

Thanks for the pointers to code that triggers this. Here's an example:
//---
switch (header.nlq_method_idc) {
case NLQ_LINEAR_DZ ->
    {
      param.f_linear_deadzone_slope = readCoefU(header, in);
      param.f_linear_deadzone_threshold = readCoefU(header, in);
      break;
    }
default ->
    throw new IllegalStateException(("nlq_method_idc: " + header.nlq_method_idc));
}
//---

In that case reference would be 'header.nlq_method_idc' which clearly is *not* a local variable. 

Apparently I misinterpreted bits == LOCAL. A look into QualifiedNameReference shows that this flag signals that the first segment (here 'header') refers to a local variable. (For obvious reasons a full qualified name can never refer to a local variable ...)

Ergo, we need more than a null check, but better detection of real references to local variables.
Comment 12 Ralf Leonhardt CLA 2021-09-18 18:13:15 EDT
I confirm that the class that has the error in my code contains two switch expressions. However, these switch expressions did not cause any problems prior to the Java 17 update (the class was running perfectly fine before I installed the update).

I am wondering what solution you would propose at this point. Should I uninstall Eclipse and then re-install without the Java 17 update? Or will switch expressions just generally not be usable anymore for the foreseeable future, and I should delete all of them in my code? This is a problem with Eclipse, not with the JDK 17, right?
Comment 13 Stephan Herrmann CLA 2021-09-19 05:13:34 EDT
(In reply to Ralf Leonhardt from comment #12)
> I confirm that the class that has the error in my code contains two switch
> expressions. However, these switch expressions did not cause any problems
> prior to the Java 17 update (the class was running perfectly fine before I
> installed the update).

Right, the bug got introduced via bug 575609, which is part of the Java 17 update.
 
> I am wondering what solution you would propose at this point. Should I
> uninstall Eclipse and then re-install without the Java 17 update?

This is an option if you don't use and specific features of Java 17.
Note that we have a "Revert" button that should facilitate this task:
  Help > About Eclipse > Installation Details > Installation History
* select a date & time
* check the list of installed features & versions
* click Revert

> Or will
> switch expressions just generally not be usable anymore for the foreseeable
> future, and I should delete all of them in my code?

Since you reported this bug (thanks!), chances are that the next milestone build already contains the fix for this particular bug. In particular the reproducer from comment 10 helps tremendously.

> This is a problem with Eclipse, not with the JDK 17, right?

Right, this is an exception in Eclipse which can be fixed entirely on our side.

And here's another option from analysis regarding comment 10:

Apparently, the bug requires requires both of these:
* a switch starting as "switch (x.y)", where x is a local variable and y a field.
* a "default ->" case

So the workaround should simply be: assign the value to a local variable before switching:
i.e., change:
   switch (x.y) {
to
   Y y1 = x.y;
   switch (y1) {

Obviously, this is no more than a workaround for the time between Java 17 update and a fix in JDT. Not recommended coding practice otherwise.
Comment 14 Ralf Leonhardt CLA 2021-09-19 05:51:33 EDT
Thanks for your help and the info. I reverted to the prior Eclipse version and will wait for the bug to be fixed before I start using Java 17.

Again, thanks for the rapid support!
Comment 15 Sravan Kumar Lakkimsetti CLA 2021-09-19 23:23:36 EDT
*** Bug 576089 has been marked as a duplicate of this bug. ***
Comment 16 Andrey Loskutov CLA 2021-09-20 04:24:12 EDT
*** Bug 576095 has been marked as a duplicate of this bug. ***
Comment 17 Andrey Loskutov CLA 2021-09-26 06:26:30 EDT
*** Bug 576267 has been marked as a duplicate of this bug. ***
Comment 18 Andrey Loskutov CLA 2021-09-26 06:28:38 EDT
Do we already have a snippet to reproduce the error? Seem to be a popular one, considering number of reports already.
Comment 19 Andrey Loskutov CLA 2021-09-26 07:11:00 EDT
*** Bug 576269 has been marked as a duplicate of this bug. ***
Comment 20 Andrey Loskutov CLA 2021-09-26 07:57:36 EDT
(In reply to Andrey Loskutov from comment #18)
> Do we already have a snippet to reproduce the error? Seem to be a popular
> one, considering number of reports already.

This reproduces the problem on master:

public class X {
	enum E { A }
	class C {
		E e = E.A;
	}
	public static void main(String[] args) {
		C c = new C();
		switch (c.e) {
		case A -> {
			System.out.println("Hello A");
		}
		default -> System.out.println("Hello E");
		}
	}
}
Comment 21 Andrey Loskutov CLA 2021-09-26 11:17:13 EDT
(In reply to Andrey Loskutov from comment #20)
> (In reply to Andrey Loskutov from comment #18)
> > Do we already have a snippet to reproduce the error? Seem to be a popular
> > one, considering number of reports already.
> 
> This reproduces the problem on master:
> 
> public class X {
> 	enum E { A }
> 	class C {

Correct (compilable) example:

public class X {
	enum E { A }
	static class C {
		E e = E.A;
	}
	public static void main(String[] args) {
		C c = new C();
		switch (c.e) {
		case A -> {
			System.out.println("Hello A");
		}
		default -> System.out.println("Hello E");
		}
	}
}

This is a regression in 4.22 IDE (after merging beta java 17 branch), 4.21 compiles the code above without errors.
Comment 22 Andrey Loskutov CLA 2021-09-26 11:58:28 EDT
Last good commit
331697d97d55cb9367bd18055a735bb6685f07b8

First bad commit
7040ea28be4a4071fc9134dca9eac6726b44cd3e

Regression from https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/184428

Looks like in SwitchStatement.analyseCode(BlockScope, FlowContext, FlowInfo) we see QualifiedNameReference instance and differently to SingleNameReference, this doesn't override Expression.localVariableBinding() - and so it always returns null. Copy & paste from SingleNameReference to QualifiedNameReference fixes the compilation. 

The only remaining question for me is: why QualifiedNameReference did not had overridden Expression.localVariableBinding(), and what is a difference between QualifiedNameReference and SingleNameReference at all? There is not a single comment explaining what those different types mean.

I will push a patch in a moment, just wondering if that is something completely gaga.
Comment 23 Eclipse Genie CLA 2021-09-26 11:59:36 EDT
New Gerrit change created: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/185835
Comment 24 Stephan Herrmann CLA 2021-09-26 12:24:49 EDT
(In reply to Andrey Loskutov from comment #22)
> Last good commit
> 331697d97d55cb9367bd18055a735bb6685f07b8
> 
> First bad commit
> 7040ea28be4a4071fc9134dca9eac6726b44cd3e
> 
> Regression from https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/184428

Right, I admitted this before.

Did you see my analysis in comment 11?

> Looks like in SwitchStatement.analyseCode(BlockScope, FlowContext, FlowInfo)
> we see QualifiedNameReference instance and differently to
> SingleNameReference, this doesn't override Expression.localVariableBinding()
> - and so it always returns null. Copy & paste from SingleNameReference to
> QualifiedNameReference fixes the compilation. 
> 
> The only remaining question for me is: why QualifiedNameReference did not
> had overridden Expression.localVariableBinding(), and what is a difference
> between QualifiedNameReference and SingleNameReference at all? There is not
> a single comment explaining what those different types mean.

That's easily explained: SimpleNameReference represents simple names like "foo" or "bar", whereas QualifiedNameReference represents qualified names like "foo.bar", "java.lang.Object" etc. (except for those cases where the grammar already determines that the reference denotes a type, in which case you will get SingleTypeReference or QualifiedTypeReference - but that's a different story).

In that light I believe QNR should never answer a non-null localVariableBinding(), because a qualified name can never refer to a local variable.

> I will push a patch in a moment, just wondering if that is something
> completely gaga.

Let's see what jenkins answers, but even if jenkins approves I think I could construct a test case the will be broken with your change.

I'll propose an alternative (more conservative) fix in a minute.
Comment 25 Andrey Loskutov CLA 2021-09-26 12:40:23 EDT
(In reply to Stephan Herrmann from comment #24)
> > Regression from https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/184428
> 
> Right, I admitted this before.
> 
> Did you see my analysis in comment 11?

Yes, but there were two commits on bug 575609, I've just noted the one that causes the regression.

> That's easily explained: SimpleNameReference represents simple names like
> "foo" or "bar", whereas QualifiedNameReference represents qualified names
> like "foo.bar", "java.lang.Object" etc. (except for those cases where the
> grammar already determines that the reference denotes a type, in which case
> you will get SingleTypeReference or QualifiedTypeReference - but that's a
> different story).

A-ha. Would be cool to update that in the javadoc for the classes above :-)

> In that light I believe QNR should never answer a non-null
> localVariableBinding(), because a qualified name can never refer to a local
> variable.

But as we see, the JDT object model at this time provides the info. So there is much bigger issue somewhere?

> Let's see what jenkins answers, but even if jenkins approves I think I could
> construct a test case the will be broken with your change.

Jenkins fails, but interestingly, only in NP analysis area - and in few cases I've checked, the analysis was improved.
Comment 26 Stephan Herrmann CLA 2021-09-26 12:49:08 EDT
(In reply to Andrey Loskutov from comment #25)
> (In reply to Stephan Herrmann from comment #24)
> [...]
> > In that light I believe QNR should never answer a non-null
> > localVariableBinding(), because a qualified name can never refer to a local
> > variable.
> 
> But as we see, the JDT object model at this time provides the info. So there
> is much bigger issue somewhere?

The issue that I got trapped in, is the fact that even a qualified name reference can resolve its *first segment* to a local variable binding, which is exactly the situation in this bug. As long as we don't jump to the conclusion (as I did), that this local variable is the meaning of the entire QNR all is fine. Or am I missing more trouble?

 
> > Let's see what jenkins answers, but even if jenkins approves I think I could
> > construct a test case the will be broken with your change.
> 
> Jenkins fails, but interestingly, only in NP analysis area - and in few
> cases I've checked, the analysis was improved.

Where I looked I saw only regressions. Which ones do you regard as improvements?
Comment 27 Stephan Herrmann CLA 2021-09-26 12:59:54 EDT
New Gerrit change created: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/185836
Comment 28 Stephan Herrmann CLA 2021-09-26 13:16:53 EDT
(In reply to Andrey Loskutov from comment #25)
> (In reply to Stephan Herrmann from comment #24)
> [...]
> > That's easily explained: SimpleNameReference represents simple names like
> > "foo" or "bar", whereas QualifiedNameReference represents qualified names
> > like "foo.bar", "java.lang.Object" etc. (except for those cases where the
> > grammar already determines that the reference denotes a type, in which case
> > you will get SingleTypeReference or QualifiedTypeReference - but that's a
> > different story).
> 
> A-ha. Would be cool to update that in the javadoc for the classes above :-)

Which javadoc? :) :)

You seem to be the first person asking for javadoc of internal AST classes (and there are many classes in this package).

My first idea would be to add to all AST classes the grammar rules that may produce the given node type. Does that sound worthwhile? Do you have a student waiting for an assignment? ;p

(Hint, Parser's consumeRule() has all the rules in comments - comments created by the parser generator, so these are correct by definition. The methods invoked from here are the ones that create AST nodes).

Also note, that the public AST is documented using javadoc, cf. e.g. org.eclipse.jdt.core.dom.QualifiedName.
Comment 30 Stephan Herrmann CLA 2021-09-26 16:55:54 EDT
(In reply to Eclipse Genie from comment #29)
> Gerrit change https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/185836 was
> merged to [master].
> Commit:
> http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/
> ?id=94f5ede8dd1c35c90c7c10a8452d01f4fc41311d

Released my version to master for 4.22 M1
Comment 31 Manoj N Palat CLA 2021-09-29 13:03:39 EDT
Verified with Eclipse 4.22 Version: 2021-12 (4.22) with Build id: I20210928-1800
Comment 32 Jesper Moller CLA 2021-09-29 16:06:31 EDT
*** Bug 576329 has been marked as a duplicate of this bug. ***
Comment 33 Eclipse Genie CLA 2021-10-24 17:33:12 EDT
New Gerrit change created: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/186875
Comment 34 Stephan Herrmann CLA 2021-10-24 17:36:22 EDT
(In reply to Eclipse Genie from comment #33)
> New Gerrit change created:
> https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/186875

It seems gerrit never triggered Java 17 tests, so one original test from bug 575609 broke unnoticed. This additional gerrit ensures we correctly handle NameReference & FieldReference alike.
Comment 35 Jay Arthanareeswaran CLA 2021-10-25 06:50:56 EDT
(In reply to Stephan Herrmann from comment #34)
> (In reply to Eclipse Genie from comment #33)
> > New Gerrit change created:
> > https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/186875
> 
> It seems gerrit never triggered Java 17 tests, so one original test from bug
> 575609 broke unnoticed. This additional gerrit ensures we correctly handle
> NameReference & FieldReference alike.

Stephan, I just updated the CI job to run at 17 instead of 16 and triggered it again. Hope you don't mind.
Comment 36 Jesper Moller CLA 2021-10-25 10:54:51 EDT
I added a failing test snippet in bug 576329, which is yet a different variation on a misunderstood LOCAL flag.
Comment 37 Stephan Herrmann CLA 2021-10-25 11:06:56 EDT
(In reply to Jay Arthanareeswaran from comment #35)
> (In reply to Stephan Herrmann from comment #34)
> > (In reply to Eclipse Genie from comment #33)
> > > New Gerrit change created:
> > > https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/186875
> > 
> > It seems gerrit never triggered Java 17 tests, so one original test from bug
> > 575609 broke unnoticed. This additional gerrit ensures we correctly handle
> > NameReference & FieldReference alike.
> 
> Stephan, I just updated the CI job to run at 17 instead of 16 and triggered
> it again. Hope you don't mind.

Thanks, indeed.
Just: 17 tests still didn't run :(
In my next attempt I also changed -Ptest-on-javase-16 into -Ptest-on-javase-17.

But then I'm expecting the build to fail due to sibling bug 575869
Comment 38 Stephan Herrmann CLA 2021-10-26 09:26:21 EDT
(In reply to Stephan Herrmann from comment #37)
> [...]
> But then I'm expecting the build to fail due to sibling bug 575869

That's exactly what happened so I'm fixing both regressions via the same gerrit https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/186875
Comment 39 Stephan Herrmann CLA 2021-10-26 10:10:47 EDT
(In reply to Jesper Moller from comment #36)
> I added a failing test snippet in bug 576329, which is yet a different
> variation on a misunderstood LOCAL flag.

Thanks, Jesper. I added this test in patch set #3, which then reminded me, that the implicit field 'length' is irrelevant for null analysis, not because it is special, but because it has a primitive type :)
Comment 41 Jesper Moller CLA 2021-10-26 12:20:20 EDT
(In reply to Stephan Herrmann from comment #39)
> (In reply to Jesper Moller from comment #36)
> > I added a failing test snippet in bug 576329, which is yet a different
> > variation on a misunderstood LOCAL flag.
> 
> Thanks, Jesper. I added this test in patch set #3, which then reminded me,
> that the implicit field 'length' is irrelevant for null analysis, not
> because it is special, but because it has a primitive type :)

Then I misunderstood the "non-null"-propagation: I understood it as if a switch is done on "x.someField", then it is certain that all switch arms must have a non-null "x" present, since evaluating "x.someField" must either succeed or cause NPE.
 
My example failed to capture this, but consider instead:

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;

// "Broken ways of null-testing"
public class Main {

    public String @NonNull[] safeArray1(String argv @Nullable []) {
      return switch(argv.length) {
        case 0 -> new String[0];
        default -> argv;
        };
    }
    
    public String @NonNull[] safeArray2(String argv @Nullable []) {
        return argv.length == 0 ? new String[0] : argv;
    }

    public String @NonNull[] safeArray3(String argv @Nullable []) {
        if (argv.length == 0) {
            return new String[0];
        }
        return argv; // A null type mismatch if it wasn't for the if-statement.
    }

}

These should trigger a potential null-pointer access on the argv.length test, but not a null type mismatch on the return, since we know from flow analysis that the argv is non-null.
Comment 42 Jesper Moller CLA 2021-10-26 12:25:49 EDT
(And it looks as if that's what happens on "master", so fine!)
Comment 43 Stephan Herrmann CLA 2021-10-26 17:44:01 EDT
(In reply to Jesper Moller from comment #41)
> (In reply to Stephan Herrmann from comment #39)
> > (In reply to Jesper Moller from comment #36)
> > > I added a failing test snippet in bug 576329, which is yet a different
> > > variation on a misunderstood LOCAL flag.
> > 
> > Thanks, Jesper. I added this test in patch set #3, which then reminded me,
> > that the implicit field 'length' is irrelevant for null analysis, not
> > because it is special, but because it has a primitive type :)
> 
> Then I misunderstood the "non-null"-propagation: I understood it as if a
> switch is done on "x.someField", then it is certain that all switch arms
> must have a non-null "x" present, since evaluating "x.someField" must either
> succeed or cause NPE.

We have two different considerations at stake.

In your case nullness of x is indeed related to the evaluation of the dot after 'x'. We don't even need to look at what comes after the dot :) so x.length, e.g., *is* relevant in this sense.

The other case poses the question, whether or not the entire expression being switched over can be null in a default case:

@NonNull Y y = switch (x.y) {
   ...
   default -> x.y;
};

This second case is where .length (instead of .y) would be irrelevant because int is never nullable (while for fields y of a reference type the spec says that null cannot enter the default branch). The implementation of this check is where the compiler threw NPE.

For an example see test_defaultDoesNotApplyToNull_field2(): field 'o' is @Nullable, but in the default of "switch (x.o)" dereferencing x.o.toString() is safe, because x.o is known to be non-null in this branch (if syntactic analysis for fields is enabled).

Makes sense?
Comment 44 Jesper Moller CLA 2021-10-26 17:47:59 EDT
(In reply to Stephan Herrmann from comment #43)

> Makes sense?

Ok, makes perfect sense. This just shows how little I actually understood of the null-checking logic when I was trying to figure out this problem.