Bug 361809 - @SuppressWarnings on existing local var produces wrong error message
Summary: @SuppressWarnings on existing local var produces wrong error message
Status: VERIFIED WONTFIX
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.8   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.8 M4   Edit
Assignee: Srikanth Sankaran CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-10-24 10:26 EDT by Paul Benedict CLA
Modified: 2011-12-05 01:57 EST (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Paul Benedict CLA 2011-10-24 10:26:57 EDT
Build Identifier: 20110916-0149

import java.util.LinkedList;
import java.util.List;
public class Test {

    public static List rawList() {return null;}
	
    public static <T> List<T> typedList() {return null;}
	
    public static void main(String[] args) {
        List<Object> list = new LinkedList<Object>();
        @SuppressWarnings("unchecked")
        list = rawList();
    }
}

This code produces error "list cannot be resolved to a type". That's wrong. The type can be resolved; removing the annotation at the previous line will allow compilation.

A better error is the existing message, "The annotation @XXX is disallowed for this location", but even that lacks clarity of what the problem is: When an annotation is allowed on a LOCAL_VARIABLE, the local variable has to be in a declaring statement; it cannot be put on an existing local variable.


Reproducible: Always
Comment 1 Ayushman Jain CLA 2011-10-24 11:44:30 EDT
Reproduced with HEAD
Comment 2 Olivier Thomann CLA 2011-10-24 11:52:48 EDT
This is clearly related to the way the recovery works and I don't think this should be changed. The code is syntactically incorrect and it is always difficult to report a good error when the syntax is wrong.

        @SuppressWarnings("unchecked")
        list = rawList();

"list" is seen as the type of a local variable and not as the local variable "list".
I would be very caution to change anything in this area.

Note that the case is important. "list" cannot be resolved to a type. "List" can be resolved.

javac reports:

Test.java:12: error: <identifier> expected
        list = rawList();
            ^
1 error

which clearly means that "list" should indeed be seen as a type name.
Comment 3 Paul Benedict CLA 2011-10-24 11:59:51 EDT
My apologies for calling the local variable "list" -- it would have been much clearer with "foo" -- so that "list" local variable and j.u.List would not have been confusing. After renaming it, the error is "foo cannot be resolved to a type".

In any event, the error reporter says the local variable can't be resolved. Oliver, are you saying it should or not should be fixed?
Comment 4 Olivier Thomann CLA 2011-10-24 12:08:11 EDT
(In reply to comment #3)
> In any event, the error reporter says the local variable can't be resolved.
> Oliver, are you saying it should or not should be fixed?
The only thing that we might want to improve if that I would also expect an error about the missing identifier. This is recovered by the statement recovery, but I would still expect the missing identifier error to be reported.
Comment 5 Paul Benedict CLA 2011-10-24 12:27:21 EDT
Can you explain the "missing identifier" part?

public static void main(String[] args) {
    List<Object> foo = new LinkedList<Object>();
    @SuppressWarnings("unchecked")
    foo = rawList();
}

The identifier, foo, exists. The annotation totally messes up the recovery; the identifier is found when the annotation is absent. The true error here is that the LOCAL_VARIABLE annotation can't be applied to an identifier that's not being declared.
Comment 6 Olivier Thomann CLA 2011-10-24 12:32:54 EDT
(In reply to comment #5)
> Can you explain the "missing identifier" part?
> 
> public static void main(String[] args) {
>     List<Object> foo = new LinkedList<Object>();
>     @SuppressWarnings("unchecked")
>     foo = rawList();
> }
> 
> The identifier, foo, exists.
foo is seen as a type name. Not as a local identifier.

Annotations are only allowed on the declaration of local variables.
Which means you need:
Annotation Type identifier ....

Open your unit with the AST view (available from the JDT/UI web page) and you will see what I mean by missing identifier.
Comment 7 Ayushman Jain CLA 2011-10-24 13:38:56 EDT
Thanks Olivier.
(In reply to comment #4)
> The only thing that we might want to improve if that I would also expect an
> error about the missing identifier.

I agree. This is because the current scenario is valid in this case

// import p.Foo;    // forgot to import Foo
public class Test {
    public static void main(String[] args) {
        @SuppressWarnings("unchecked")
        Foo /*expecting identifier*/ = rawList();   // Foo was an intended type
    }
}

So the "expecting identifier" was not parsed and can be reported.
Comment 8 Paul Benedict CLA 2011-10-24 14:18:32 EDT
(In reply to comment #6)
> foo is seen as a type name. Not as a local identifier.

Agreed. I installed AST view and see that now.

However, the error message shouldn't make this code look like I was trying to create a new local variable. While "expected identifier" is certainly one valid interpretation of the code, it's not what I was trying to do at all. The comment from comment #5 is really what I would expect the compiler to give me: "Annotations are only allowed on the declaration of local variables."

Couldn't you implement this kind of algorithm?
1) If the error is "expected identifier"...
2) And an annotation precedes the type...
3) And the type matches the name of a local variable...
3) Report "Annotations are only allowed on the declaration of local variables."
Comment 9 Ayushman Jain CLA 2011-10-25 01:27:54 EDT
(In reply to comment #8)
> comment from comment #5 is really what I would expect the compiler to give me:
> "Annotations are only allowed on the declaration of local variables."
> 
> Couldn't you implement this kind of algorithm?

Unfortunately, in this case the problem is that the parser itself is not able to make sense of the broken line, and recover any syntactical structure out of it, other than assuming "list" to be a type. Parser only knows the rules of the grammar. 

As said, the best we can do is to evaluate feasibility of giving a missing identifier error.
Comment 10 Srikanth Sankaran CLA 2011-11-21 02:22:39 EST
(In reply to comment #8)
> (In reply to comment #6)
> > foo is seen as a type name. Not as a local identifier.
> 
> Agreed. I installed AST view and see that now.
> 
> However, the error message shouldn't make this code look like I was trying to
> create a new local variable. While "expected identifier" is certainly one valid
> interpretation of the code, it's not what I was trying to do at all.

It is very hard for a compiler to divine what the programmer intended. The error
message produced at the moment looks just valid to me. Producing in addition
a secondary error is frought with peril: syntax errors can in general result
in a program being so structurally broken that, if we allow secondary errors,
it is very hard to ensure quality of the diagnostics.

Planning to close this as WONTFIX.
Comment 11 Srikanth Sankaran CLA 2011-11-21 03:19:02 EST
(In reply to comment #4)
> (In reply to comment #3)
> > In any event, the error reporter says the local variable can't be resolved.
> > Oliver, are you saying it should or not should be fixed?
> The only thing that we might want to improve if that I would also expect an
> error about the missing identifier. This is recovered by the statement
> recovery, but I would still expect the missing identifier error to be reported.

On 3.8 stream top of trunk, this already works ok as described above: 

For the record, the program below produces two messages:

import java.util.LinkedList;
import java.util.List;
public class Test {

    public static List rawList() {return null;}

    public static <T> List<T> typedList() {return null;}

    public static void main(String[] args) {
        List<Object> list = new LinkedList<Object>();
        @SuppressWarnings("unchecked")
        list = rawList();
    }
}

- list cannot be resolved to a type
- Syntax error on token "list", VariableDeclaratorId expected after 
	 this token

while the one below:

import java.util.LinkedList;
import java.util.List;
public class Test {

    public static List rawList() {return null;}

    public static <T> List<T> typedList() {return null;}

    public static void main(String[] args) {
        List<Object> list = new LinkedList<Object>();
        @SuppressWarnings("unchecked")
        List = rawList();
    }
}

elicits just one:

- Syntax error on token "List", VariableDeclaratorId expected after this 
  token

Resolving as INVALID.
Comment 12 Satyam Kandula CLA 2011-12-05 01:57:43 EST
Verified for 3.8M4 using build I20111202-0800