Bug 142653 - [1.5][compiler] JDT Internal Compiler Error: NullPointerException in MethodVerifier.computeInheritedMethods(), Eclipe 3.2RC4
Summary: [1.5][compiler] JDT Internal Compiler Error: NullPointerException in MethodVe...
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.2   Edit
Hardware: PC Windows XP
: P3 major (vote)
Target Milestone: 3.2 RC6   Edit
Assignee: Kent Johnson CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-05-18 17:50 EDT by Missing name Mising name CLA
Modified: 2006-05-26 11:33 EDT (History)
6 users (show)

See Also:


Attachments
Proposed patch (5.84 KB, patch)
2006-05-19 06:58 EDT, Philipe Mulet CLA
no flags Details | Diff
Better patch (14.06 KB, patch)
2006-05-19 07:04 EDT, Philipe Mulet CLA
no flags Details | Diff
Patch (16.00 KB, patch)
2006-05-19 14:26 EDT, Kent Johnson CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Missing name Mising name CLA 2006-05-18 17:50:26 EDT
When opening the workspace of a Java 1.5 project developed under Eclipse 3.1 under the latest 3.2RC4 (3.2.0 Build I20060512-1600) an internal compiler error is reported via an error marker highlighting the first character of a Java source file.  The stack trace contained within the marker is as follows:

Internal compiler error
java.lang.NullPointerException
	at org.eclipse.jdt.internal.compiler.lookup.MethodVerifier.computeInheritedMethods(MethodVerifier.java:507)
	at org.eclipse.jdt.internal.compiler.lookup.MethodVerifier.computeInheritedMethods(MethodVerifier.java:392)
	at org.eclipse.jdt.internal.compiler.lookup.MethodVerifier.verify(MethodVerifier.java:636)
	at org.eclipse.jdt.internal.compiler.lookup.MethodVerifier15.verify(MethodVerifier15.java:544)
	at org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.verifyMethods(SourceTypeBinding.java:1594)
	at org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope.verifyMethods(CompilationUnitScope.java:756)
	at org.eclipse.jdt.internal.compiler.Compiler.process(Compiler.java:591)
	at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:411)
	at org.eclipse.jdt.internal.core.builder.AbstractImageBuilder.compile(AbstractImageBuilder.java:300)
	at org.eclipse.jdt.internal.core.builder.BatchImageBuilder.compile(BatchImageBuilder.java:217)
	at org.eclipse.jdt.internal.core.builder.AbstractImageBuilder.compile(AbstractImageBuilder.java:237)
	at org.eclipse.jdt.internal.core.builder.BatchImageBuilder.build(BatchImageBuilder.java:56)
	at org.eclipse.jdt.internal.core.builder.JavaBuilder.buildAll(JavaBuilder.java:249)
	at org.eclipse.jdt.internal.core.builder.JavaBuilder.build(JavaBuilder.java:169)
	at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:603)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:37)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:167)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:201)
	at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:230)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:37)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:233)
	at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:252)
	at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:285)
	at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:145)
	at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:208)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:58)

The class in the source file is defined:
  public class Child extends Parent<Type> {}

The parent source is defined:
  public abstract class Parent<Type> extends Grandparent<Type> implements IParent {} 

Removing the 'extends Parent' inheritence from the child gets rid of the internal compiler error, but generates a different one in another class:

Internal compiler error
java.lang.NullPointerException
	at org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding.implementsInterface(ReferenceBinding.java:812)
	at org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding.isCompatibleWith0(ReferenceBinding.java:937)
	at org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding.isCompatibleWith(ReferenceBinding.java:890)
	at org.eclipse.jdt.internal.compiler.ast.ReturnStatement.resolve(ReturnStatement.java:215)
	at org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.resolveStatements(AbstractMethodDeclaration.java:432)
	at org.eclipse.jdt.internal.compiler.ast.MethodDeclaration.resolveStatements(MethodDeclaration.java:179)
	at org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.resolve(AbstractMethodDeclaration.java:403)
	at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.resolve(TypeDeclaration.java:1047)
	at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.resolve(TypeDeclaration.java:1094)
	at org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration.resolve(CompilationUnitDeclaration.java:353)
	at org.eclipse.jdt.internal.compiler.Compiler.process(Compiler.java:594)
	: (continues as previous trace)
	
As it stands I cannot continue development in this version of Eclipse and I have to revert to my previous configuration.
Comment 1 Philipe Mulet CLA 2006-05-18 17:56:07 EDT
Please provide steps to reproduce.
Too late for RC5 anyway.

Comment 2 Philipe Mulet CLA 2006-05-18 18:05:20 EDT
Please reopen once steps are available.
Comment 3 Missing name Mising name CLA 2006-05-18 19:07:48 EDT
The problem seems to be caused by Eclipse not gracefully handling an inconsistent type hierarchy.  I can recreate the first internal error by defining the following classes and interfaces in separate files:

public class Child extends Parent<Object> {}
public abstract class Parent<T> extends Grandparent<T> implements IParent {}
public interface IParent<T> extends IGrandparent<T> {}
public abstract class Grandparent<T> implements IGrandparent<T> {}
public interface IGrandparent<T> {}

In this case Eclipse points out the inconsistent type hierarchy with a marker on Parent.java ("The interface IGrandparent cannot be implemented more than once with different arguments: IGrandparent<T> and IGrandparent").  (No such error was given in my original code - the only error was the internal compiler fault).

An error can be seen on "line 0" of Child.java as before:

Internal compiler error
java.lang.NullPointerException
	at org.eclipse.jdt.internal.compiler.lookup.MethodVerifier.computeInheritedMethods(MethodVerifier.java:507)
	:
	
The error in the source can be resolved by modifying the Parent to use type parameters in its interface implementation:

public abstract class Parent<T> extends Grandparent<T> implements IParent<T> {}

Making a similar correction in my project also stops this internal error.  I have been unable to reproduce the second stack trace, however.
Comment 4 Philipe Mulet CLA 2006-05-19 03:15:45 EDT
The two cases are consequence of the same bug. An array of superinterfaces contain null values.

These are likely coming from the collision detected before (cannot implement twice the same interface in different parameterized form).
Comment 5 Philipe Mulet CLA 2006-05-19 04:16:08 EDT
The problem comes from late removal of colliding superinterfaces from the type binding; at a stage where parameterized type instances already got created way before this (and did not get readjusted).

Given this change was made late, and also causes grief to other places, e.g. DOM AST; I believe we should reintroduce them back and improve the verifier to ignore them.
Comment 6 Philipe Mulet CLA 2006-05-19 06:33:34 EDT
One thing to consider is having colliding superinterfaces being persisted in (problem) classfiles. This shouldn't be an issue, since through binary compatibility scenari, the same may occur with valid classfiles (i.e. forgot to recompile some supertype after a subclass change).

Tagging for 3.2.1. Though the situation is not ideal, this is a sensitive change to perform, and we need to check for ripples, even in dependent components (what about refactoring etc...). 
Currently, we have an internal exception when compiling incorrect code, resulting in an extra marker being created. We are not rejecting valid code, but rather are not optimally handling incorrect code. Still we want to address it asap, but I don't think it qualifies as a stop ship issue for 3.2.0.
Comment 7 Philipe Mulet CLA 2006-05-19 06:58:26 EDT
Created attachment 42000 [details]
Proposed patch

The patch is no longer altering the binding superinterfaces as a side effect of the collision check.
It also defers the check until method verification occurs, since this is where the non colliding interface list is needed to avoid complaining unnecessarily about nameclash issues...
Comment 8 Philipe Mulet CLA 2006-05-19 06:58:48 EDT
Kent - what do you think ?
Comment 9 Philipe Mulet CLA 2006-05-19 07:00:15 EDT
Added GenericTypeTest#test0989-0992 + MethodVerifyTest#test088
Comment 10 Philipe Mulet CLA 2006-05-19 07:04:57 EDT
Created attachment 42001 [details]
Better patch

Slight improvement, avoid unnecessary work when compliance < 1.5
Comment 11 Philipe Mulet CLA 2006-05-19 12:17:19 EDT
Reassign to Kent. After discussion, we will make the fix a little bit better to reduce noise in case of collisions.
e.g.
import java.util.*;
public class X extends X2 {}
abstract class X2 extends X3 implements List<String> {}
abstract class X3 implements List<Thread> {}

here we shouldn't report any missing method implementation, until the collisions have been addressed. With RC4, we complain about missing List<Thread> methods, with my patch we complain about missing List<Thread> AND List<String> methods.

Also, once this bug is addressed, we should close bug 138671 (DOM with proper test), and bug 138887. 
Bug 138671 is a regression over 3.1, and we need to double check that JDT/UI is correctly behaving (in case they worked around the regression).
CC'ing Martin about later concern.
Comment 12 Philipe Mulet CLA 2006-05-19 12:18:18 EDT
Because of NPE possibilities, I am wondering about the consequences on DOM clients, like refactoring. We may want to address this for 3.2RC6.
Comment 13 Kent Johnson CLA 2006-05-19 14:26:04 EDT
Created attachment 42060 [details]
Patch

Philippe - please check this patch. It finds all the superinterfaces and skips the ones that have the same erasure.

passes all of your new tests without any secondary errors
Comment 14 Philipe Mulet CLA 2006-05-19 15:53:04 EDT
Patch looks good. Shouldn't you use a tagbit to retain the presence of collisions, and thus avoid expensive work during method verification ?
Comment 15 Philipe Mulet CLA 2006-05-22 10:11:33 EDT
Note: The bit usage would only be a small performance improvement. Nothing critical (ie. could occur post 3.2.0).
Comment 16 Philipe Mulet CLA 2006-05-22 10:25:33 EDT
Martin/Dani - would you vote for fixing this in RC6 ?
Comment 17 Philipe Mulet CLA 2006-05-22 10:30:11 EDT
Dani/Martin - current behavior (NPE) is a regression over 3.1.2.
Comment 18 Philipe Mulet CLA 2006-05-22 10:37:41 EDT
Mike - pls cast your vote for RC6.

Basically, in RC1 another fix did introduce a regression in a negative scenario; resulting in causing a NPE in the compiler. 

With the patch, the behavior is even better than in 3.1, since less secondary errors are being produced (ie. no complaint for unimplemented abstract methods from offending superinterfaces). The fix is safe.

This fix could either go in for 3.2.0 or 3.2.1; candidating for RC6 since the regression got promptly identified, and we have a good fix at hand.
Also this is correcting the DOM AST defficiency (small contract change) introduced at RC1 as well, and documented in bug 138671 (DOM) and bug 138887. 
Comment 19 Martin Aeschlimann CLA 2006-05-22 12:04:49 EDT
Discussed the patch with Philippe, I couldn't prove him wrong (So far! :-)).

+1 for 3.2 RC6 as the current code (introduced in Rc2) would return 'null' elements as super interfaces. According to Philippe, this would also be visible in the DOM AST which would be unexpected and result in NPE's in our code.

I wouldn't mind having a more minimal patch at this stage, e.g. don't try to reduce the number of emmited 'type contains unimplemented methods' errors.
Comment 20 Philipe Mulet CLA 2006-05-22 12:20:47 EDT
Kent - what about only fixing ClassScope for 3.2.0, and the method verifier for 3.2.1 ? Afterall, minimizing secondary errors is deluxe... in 3.1 we had half the secondary issues.

I would second this request for RC6; since this makes the fix much safer/simpler.
Comment 21 Dani Megert CLA 2006-05-22 12:27:28 EDT
>I wouldn't mind having a more minimal patch at this stage,
Same here. Could we see a patch that only contains the minimum to fix the reported NPE? More clean up can be done post 3.2.
Comment 22 Kent Johnson CLA 2006-05-23 09:54:20 EDT
I'll look into the smaller fix, but the patch is not that scary.

90% of the code in findSuperinterfaceCollisions is copied from computeInheritedMethods and over half of the patch is new tests.
Comment 23 Mike Wilson CLA 2006-05-23 13:44:04 EDT
I'll leave it to the rest of you to decide whether a more minimal patch is a better answer at this point. I reviewed the latest patch with Kent, and agree that it looks scarier than it really is.

I'm also a bit worried that, for people who actually hit the problem, the secondary errors that will be produced without the verifier fix will be confusing.
Comment 24 Kent Johnson CLA 2006-05-23 14:02:15 EDT
The smallest possible change is a one line change to ClassScope in this block of code in checkParameterizedSuperTypeCollisions():

nextOtherInterface: for (int j = 0; j < i; j++) {
  ReferenceBinding two = interfaces[j];
  if (two == null) continue nextOtherInterface;
  if (hasErasedCandidatesCollisions(one, two...)) {
    interfaces[i] = null; <<<< should be j instead of i
    count--;
    continue nextInterface;
  }
}

But given bug 138671, we should at least take the full change to ClassScope from the existing patch, which no longer removes the interface.

I would prefer not to remove the changes to the MethodVerifier15, but if we do then 2 of the tests in the patch need to be modified to report 4 & 6 additional secondary errors that make it more difficult to see the root cause of the problem (the duplicate interfaces with different arguments).

The changes to the verifier are mostly copied code from computeInheritedMethods so they are not as scary as they look.
Comment 25 Dani Megert CLA 2006-05-24 03:13:43 EDT
>But given bug 138671, we should at least take the full change to ClassScope
>from the existing patch, which no longer removes the interface.
I'd vote for the minimal patch in ClassScope for 3.2 RC6 and doing the full fix in 3.2.1.
Comment 26 Martin Aeschlimann CLA 2006-05-24 04:32:54 EDT
+1 to take full change to ClassScope from the existing patch and leave the MethodVerifiers as is. 
I also reviewed the full patch and believe that the changes in MethodVerifier15 are all fine, but I wouldn't want to take the risk that interfaces are wrongly eliminated and no 'unimplemented method' error is generated.
Comment 27 Mike Wilson CLA 2006-05-24 09:38:12 EDT
this makes sense to me. +1 to putting in the reduced patch for now, and the rest for 3.2.1
Comment 28 Kent Johnson CLA 2006-05-24 11:21:21 EDT
Released ClassScope only change with additional secondary errors in tests to HEAD for RC6.

Released ClassScope + MethodVerifier changes to 3.2.1 branch.

Closed bug 138671 and bug 138887 since they are fixed with the ClassScope change.
Comment 29 Olivier Thomann CLA 2006-05-26 11:33:43 EDT
Verified in I20060526-0010 for 3.2RC6