Closed
Description
I tried this code:
fn main() {
let x = 5
()
}
I expected to see this happen:
error: expected `;`, found `}`
--> src/main.rs:2:14
|
2 | let x = 5
| ^ help: add `;` here
3 | }
| - unexpected token
One error occurs from the missing semicolon.
Instead, this happened:
error: expected `;`, found `}`
--> src/main.rs:4:7
|
4 | ()
| ^ help: add `;` here
5 | }
| - unexpected token
error[E0618]: expected function, found `{integer}`
--> src/main.rs:2:13
|
2 | let x = 5
| _____________^
3 | |
4 | | ()
| |______- call expression requires function
An additional unexpected error occurs when when I obviously do not want to invoke a closure. Also note that the semicolon error is after the supposed closure invocation, when I would expect it to be after the let x = 5
.
Meta
Occurs on latest stable and nightly.
Metadata
Metadata
Assignees
Labels
Area: Messages for errors, warnings, and lintsCategory: This is a bug.Diagnostics: Confusing error or lint; hard to understand for new users.Diagnostics: An error or lint that doesn't give enough information about the problem at hand.Relevant to the compiler team, which will review and decide on the PR/issue.
Activity
fmease commentedon Jan 6, 2023
lyming2007 commentedon Jan 6, 2023
The compiler would consider the case
the same as
I think it's hard to determine if the user wants invoke a closure or not by writing the "()" to the next line.
Rust allows syntax like this(actually a lot of languages allow this type of syntax)
fmease commentedon Jan 6, 2023
We should definitely be able to look at the spans of the callee and the argument list, determine if they are on separate lines (via the
SourceMap
) & don't originate from a macro expansion and if so at least add a note to the diagnostic suggesting to add a semicolon. Of course, there will always be false positives.estebank commentedon Jan 6, 2023
The case should be handled in both the parser and the call error. In the parser we can't be certain that the call expression is incorrect, except for maybe literals, but if you had
we are back to ambiguity, so that should be handled in E0618 and suggest a semicolon there as well. You could also have
which would parse successfully but fail only in the call.
lyming2007 commentedon Jan 6, 2023
@rustbot claim
Noratrieb commentedon Jan 6, 2023
When adding a nice parser error you have to make sure that you never emit a parser error for valid rust syntax.
So for the example Esteban described above handling it in the parser is fine since the
let
statement is missing a semicolon, making it invalid syntax.But you have to make sure that something like
doesn't give a parser error but only errors during type checking.
This is because of macros, which may transform code that is valid syntax but invalid semantically into something entirely valid.
estebank commentedon Jan 7, 2023
At the very least, these cases should be handled
Ezrashaw commentedon Jan 7, 2023
I guess I should also be clear that the suggestion currently provided by rustc could never be correct: function (and closure) names can't start with integer
fmease commentedon Jan 7, 2023
The diagnostics currently emitted by the compiler are absolutely correct: An integer cannot be called and the let-statement must be followed by a semicolon. Indeed, identifiers (“function (and closure) names”) cannot start with a digit. However, this is not relevant here: Syntactically speaking, the callee (the thing being called) in a call expression can be an arbitrary expression. Consider
(T {} + "")()
(this might even be well-typed depending on the definition ofT
and itsimpl
s).So
5()
is syntactically well-formed but semantically it is not (according to the trait solver) as there is no primitive integer type (e.g.i32
) that implementsFnOnce
or friends. Technically speaking,core
could very well add aFnOnce
implementation fori32
that makes5()
semantically well-formed, too.This is the reason why you see the error messages you posted. Edit: I hope it's already clear from context but I'd like to emphasize that I am not saying that the diagnostics as emitted today should stay the way they are (we should definitely suggest to add a
;
as mentioned above), I am just trying to clarify the semantics and disputing the quoted statement.Ezrashaw commentedon Jan 7, 2023
Ahh right, I forget briefly that function calls could be on values, I was thinking of the integer literal being seen as an identifier only (and of course integer identifiers don't exist). Silly me!
estebank commentedon Jan 7, 2023
@Ezrashaw the point you're making is why we can proactively catch the "literal followed by ()" case in the parser, and avoid the second, unnecessary "invalid call" error. But for the general case, where the parser doesn't have enough context (a, b and c in my examples), we would have to emit two errors, or delay the parse error until resolve.
lyming2007 commentedon Jan 9, 2023
@estebank @Ezrashaw
According to the discussion, the current diagnostics emitted by the compiler are correct. Can we close the issue now?
estebank commentedon Jan 9, 2023
@lyming2007 the compiler errors are correct, but they are misleading, so we'll put some effort to improve the output to make it clear what is happening to everyone, regardless of expertise level, at a glance.
lyming2007 commentedon Jan 9, 2023
ok. So we still let the compiler emit 2 diagnostics, one is from the parser, another one is error[E0618]. How about the output being like this?
Which won't be misleading the user to program code like
5()
;Ezrashaw commentedon Jan 9, 2023
@estebank @lyming2007 Hmm, I haven't really been keeping up to date with this so this might not be ideal/possible but:
;
, found(
". We shouldn't leave out the()
here.fmease commentedon Jan 10, 2023
Disclaimer: I might be biased by the phrasing of existing diagnostics. The error message expected
;
, found(
looks like it's describing a syntax error, even though it's not (it's a type error) as I've previously mentioned. The wording expected / found [token] is exclusively used by the parser as far as I know. If I see that message I assume that annotating the container with#[cfg(FALSE)]
or adding the CLI flag-Zparse-only
would not make the error go away. Because of this, I caution against using such phrasing.I expect it to look similar to:
Ezrashaw commentedon Jan 10, 2023
@fmease Sorry, I should have been more clear:
doesn't really make sense to me, it leaves out the
()
which is obviously important in this context. EDIT: AFAIK, it still remains in the parser, and it definitely is still a syntax error.As for your suggested diagnostic, the proposed suggestion doesn't seem quite right in terms of wording. Adding a semicolon does not fix the error; it does not provide a function, but rather makes the error go away by removing the expectation of a function in the first place. This has to be explained to the user, otherwise it just looks even more confusing.
;
that parses as function call #114474Detect missing `;` that parses as function call
Rollup merge of rust-lang#114474 - estebank:missing-semi, r=compiler-…