Bug 537212 - Raise visibility of syntax error when secondary error marker contains the region of the syntax error
Summary: Raise visibility of syntax error when secondary error marker contains the reg...
Status: REOPENED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 4.8   Edit
Hardware: PC Linux
: P3 enhancement (vote)
Target Milestone: ---   Edit
Assignee: JDT-UI-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-07-20 01:53 EDT by Luke Hutchison CLA
Modified: 2021-01-04 03:34 EST (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Luke Hutchison CLA 2018-07-20 01:53:55 EDT
The following code is incorrect, because the precedence of the ternary operator (?:) is higher than assigment (=). However, the error message given is not for assignment or the ternary operator, but the less than or equal operator (<=): "The operator <= is undefined for the argument type(s) InputStream, FileInputStream"

public abstract class BadWarning {
    InputStream inputStream;
    
    InputStream openInputStream() { 
        return inputStream != null
            ? inputStream
            : inputStream = new FileInputStream(path);  // Error here
    }
}

According to Java precedence, this should actually evaluate to

        return (inputStream != null
            ? inputStream
            : inputStream) = new FileInputStream(path);

and the error should be "The left-hand side of an assignment must be a variable" -- so there seem to be two problems here: a wrong error being shown, and the correct error not being shown.
Comment 1 Luke Hutchison CLA 2018-07-20 01:57:24 EDT
(Sorry, there is a missing "throws IOException" and a missing "String path" parameter to the function openInputStream -- but adding these does not change the error.)

If you change the order of the ternary operator, no error is shown, as expected:

        return inputStream == null 
            ? inputStream = new FileInputStream(path)
            : inputStream;
Comment 2 Stephan Herrmann CLA 2018-07-20 04:31:29 EDT
For the records, the compiler reports:

        : inputStream = new FileInputStream(path);  // Error here
                      ^
Syntax error on token "=", <= expected


The error "The left-hand side of an assignment must be a variable" is a semantic error, that is detected during resolution, which in turn requires that the sources have been fully parsed. Due to the syntax error that is not possible.


To verify the syntax error: after 'return' we need an expression. Comment 0 suggests to interpret the rest after 'return' as an AssignmentExpression, where the LHS is a ConditionalExpression.

Here's the rule for AssignmentExpression:

AssignmentExpression:
    ConditionalExpression
    Assignment
Assignment:
    LeftHandSide AssignmentOperator Expression
LeftHandSide:
    ExpressionName
    FieldAccess
    ArrayAccess

We'd need to consume the conditional expression as a LeftHandSide, but there's no match. Now *parsing* goes left-to-right trying to find the largest legal chunk of text. Before we look at the '=' everything is legal, indeed, but after "'return' ConditionalExpression" there's no rule allowing a '=' token. Hence that's where we report the error.

We could argue that the reported error is not "optimal", but to determine an "optimal" message we'd need to know what the author of the code *intended* to write, to tell her, what exactly must be changed. Obviously, knowing the author's intention is beyond the compiler.

Prior to semantic analysis any binary operator like '<=' is indeed a proper repair to change the broken AssignmentExpression into a legal BinaryExpression.

Long story short:
- The expectation to see "The left-hand side of an assignment must be a variable" is wrong, because semantic analysis can't even start in the presence of a syntax error.
- Alternative syntax errors are possible, but the parser cannot positively know which error is most helpful for the user.
- The given error is correct.

=> Not a bug.
Comment 3 Luke Hutchison CLA 2018-07-20 05:04:05 EDT
OK, not a bug, but rather than picking a random binary operator for repair, maybe you could pick an "undefined" binary operator, and that way, report a more useful error message in this case?

The user should not need to know the exact grammar rules that the compiler is using, or even more so, the exact repair rules the compiler is using. I see your point as a compiler engineer, however from the user perspective, when there is no "<=" whatsoever in the code, this error *looks* plain wrong, whether or not it is as justifiable than any other error that could be given involving a randomly-chosen binary operator.
Comment 4 Till Brychcy CLA 2018-07-20 05:07:53 EDT
I agree "The left-hand side of an assignment must be a variable" cannot be expected.

But I think the main problem is that the actual syntax error "Syntax error on token "=", <= expected" is only visible in the problems view - as hover you see the "The operator <= is undefined for the argument type(s) InputStream, FileInputStream" which is based on a symbol that error recovery invented.

I wonder if we can somehow avoid creating the secondary error?
Comment 5 Stephan Herrmann CLA 2018-07-21 09:51:28 EDT
(In reply to Till Brychcy from comment #4)
> I agree "The left-hand side of an assignment must be a variable" cannot be
> expected.
> 
> But I think the main problem is that the actual syntax error "Syntax error
> on token "=", <= expected" is only visible in the problems view - as hover
> you see the "The operator <= is undefined for the argument type(s)
> InputStream, FileInputStream" which is based on a symbol that error recovery
> invented.
> 
> I wonder if we can somehow avoid creating the secondary error?

Thanks for retesting. I only tested via batch compilation, but the difference between different compilation modes looks wrong.
Comment 6 Stephan Herrmann CLA 2018-07-28 09:42:55 EDT
I can reproduce the secondary error in a JUnit based on project.build(..) and project.findMarkers(..)

The '<=' operator is indeed invented during syntax recovery. I don't see a way to influence this, nor is the replacement plain wrong. In fact it helps minimize secondary errors, as it establishes correct syntax, while we don't have sufficient information at that point how to create a replacement that's also semantically valid.

The usability problem lies more in the UI:

In hovers on left and right rulers we correctly see "Multiple markers at this line" including the syntax error. It is just quite difficult to see the syntax error in the editor, because its region is much smaller than the region of the secondary error.

So, how can we make the syntax error more visible?

- Suppress semantic errors in the very statement having the syntax error?
  (so far, only the MethodDeclaration is marked as having a syntax error,
   not the statement).

- Improve selection of the most severe marker to show in the hover?

No low hanging fruit for M2 and in fact not even a bug, just a request to improve usability.
Comment 7 Luke Hutchison CLA 2018-07-28 15:25:59 EDT
I appreciate you taking a deeper look at this. Isn't it almost always appropriate to show syntax errors with precedence over overlapping semantic errors, since in this case, the semantic errors are probably a "domino effect" of the syntax errors?
Comment 8 Stephan Herrmann CLA 2018-07-28 17:13:47 EDT
(In reply to Luke Hutchison from comment #7)
> I appreciate you taking a deeper look at this. Isn't it almost always
> appropriate to show syntax errors with precedence over overlapping semantic
> errors, since in this case, the semantic errors are probably a "domino
> effect" of the syntax errors?

Wrt "showing" in the editor: yes. My current thinking, however, is: continue reporting them (in Problems view and rulers), just change visualization in the editor, in case a syntax error and a semantic error meet on the same line.

At this point it's less of a conceptual question, more a technical one: Where the information is shown in the editor we may not have the necessary information about the distinction syntactic / semantic error.

And then it's a UI question: should we completely suppress the semantic error in the editor? Perhaps a general hint about "more problems at this location" might help - also for situations where two semantic errors overlap.

OR, should we complete suppress reporting those "secondary" errors in the first place? In that case, "meet on the same line" may not be appropriate distinction, at this level we should more likely silence semantic errors for the enclosing statement. We have precedents like: don't report flow-related problems in the presence of resolve errors. etc.
Comment 9 Jay Arthanareeswaran CLA 2018-07-30 06:19:13 EDT
(In reply to Stephan Herrmann from comment #8)
> OR, should we complete suppress reporting those "secondary" errors in the
> first place? In that case, "meet on the same line" may not be appropriate
> distinction, at this level we should more likely silence semantic errors for
> the enclosing statement. We have precedents like: don't report flow-related
> problems in the presence of resolve errors. etc.


We can do that if we have more such cases and it does seem like an easy way out. However, Would there ever be cases where the secondary error could be useful too?
Comment 10 Manoj N Palat CLA 2018-08-16 00:30:20 EDT
Bulk move out of 4.9
Comment 11 Luke Hutchison CLA 2018-08-16 04:08:09 EDT
The bug title says "syntax error" twice.. I think the first should say "semantic error"?
Comment 12 Stephan Herrmann CLA 2018-08-16 18:29:04 EDT
(In reply to Luke Hutchison from comment #11)
> The bug title says "syntax error" twice.. I think the first should say
> "semantic error"?

No, I meant what I wrote :)
Comment 13 Stephan Herrmann CLA 2020-12-27 17:09:49 EST
For a similar issue consider:

//---
package bug;

import java.util.Arrays;
import java.util.List;

public class Opstar {
	void m2(Object o1, Object o2) {
		List<Number> list = Arrays.asList(((Number) o1, (Number) o2));
	}
}
//---

The compiler signals an error and when you hover over the error location, all you see is:
"The operator * is undefined for the argument type(s) java.lang.Number, java.lang.Number"

Since the source contains no '*' whatsoever, this leaves the user tearing their hair or biting their keyboard.

Only when you hover the error icon in the ruler or look into the Problems view you see the primary error:

"Syntax error on token ",", * expected"

(which happens due to a bogus pair of enclosing parentheses).


This example supports the idea that syntax errors should be shown in the editor with priority.

Since the editor never displays hovers for several errors at the same location, I think it would be fine to simply not show any semantic errors that overlap/interact with a syntax error location, to at least ensure that all syntax errors are discoverable in the editor.