RFR: 8232765: NullPointerException at Types.eraseNotNeeded() when compiling a class
Maurizio Cimadamore
mcimadamore at openjdk.java.net
Wed Apr 21 14:35:40 UTC 2021
On Wed, 21 Apr 2021 14:24:32 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:
>> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java line 3501:
>>
>>> 3499: eType,
>>> 3500: List.nil());
>>> 3501: Type returnType = types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym);
>>
>> I know you closed this PR - just wanted to leave a comment: issuing this kind of type-checking errors in Lower is unusual. This kind of stuff should be caught in earlier (e.g. in Attr) - and, over the years we've been making efforts to move all error generation in the front-end; note than when using compiler through the compiler API, you might not run Lower (and all desugaring steps) so you might miss errors if these are generated too late.
>>
>> That said, surely the check:
>>
>>
>> Type returnType = types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym);
>> ```
>>
>> Must be somewhere in Attr?
>
> So, in `Attr` we check that the class implements `Iterable`. In this case it does, but there's an incompatible override. That issues an error as expected, so compiling the provided test case:
>
>
> public class T8232765 {
> public void test(String[] args) {
> MyLinkedList<Integer> list = new MyLinkedList<>();
> for (int x : list)
> System.out.print(x);
> }
> }
> class MyLinkedList<T> implements java.lang.Iterable<T> {
> public void iterator() {}
> };
>
> Does not result in a crash.
>
> I suspect the issue in JBS is more subtle, and involves, perhaps, separate compilation? I find this very odd - typically javac stops at a phase (e.g. Attr) if one or more files had errors in that phase. In this case we have a bad implementation of `Iterable`, so we should not be able to go past `Attr`.
Ok, I see where I went wrong. I can reproduce the crash - the problem I had was related to `public` appearing in a file with wrong name.
So, the issue occurs when two classes are defined in the same source. In that case, we advance T8232765 through the compiler pipeline almost independently of MyLinkedList. The only thing happening for MyLinkedList is the typeEnter step - but no Attr is performed, so no overriding checks.
If the `simple` compile policy is used, no crash occurs:
javac -XDcompilePolicy=simple -XDverboseCompilePolicy=true Test.java
[attribute T8232765]
[attribute MyLinkedList]
Test.java:8: error: MyLinkedList is not abstract and does not override abstract method iterator() in Iterable
class MyLinkedList<T> implements java.lang.Iterable<T> {
^
where T is a type-variable:
T extends Object declared in class MyLinkedList
Test.java:9: error: iterator() in MyLinkedList cannot implement iterator() in Iterable
public void iterator() {}
^
return type void is not compatible with Iterator<T#2>
where T#1,T#2 are type-variables:
T#1 extends Object declared in interface Iterable
T#2 extends Object declared in class MyLinkedList
2 errors
This has come up again in the past: should the *simple* policy be the default?
-------------
PR: https://git.openjdk.java.net/jdk/pull/2099
More information about the compiler-dev
mailing list