Code change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: I expected to see this happen: One error occurs from the missing semicolon. Instead, this happened: 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 . Occurs on latest stable and nightly. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
label A-diagnostics D-newcomer-roadblock D-terse
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)
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 ) & 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.
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.
claim
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 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.
At the very least, these cases should be handled
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
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 (this might even be well-typed depending on the definition of and its s). So is syntactically well-formed but semantically it is not (according to the trait solver) as there is no primitive integer type (e.g. ) that implements or friends. Technically speaking, could very well add a implementation for that makes 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.
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!
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.
According to the discussion, the current diagnostics emitted by the compiler are correct. Can we close the issue now?
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.
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 ;
Hmm, I haven't really been keeping up to date with this so this might not be ideal/possible but: This parser error is, IMO, wrong. It should say "expected , found ". We shouldn't leave out the here.
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 or adding the CLI flag would not make the error go away. Because of this, I caution against using such phrasing. I expect it to look similar to:
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.

Related discussion:
text: <ins> // run-rustfix #![allow(dead_code, unused_variables, path_statements)] fn a() { let x = 5; let y = x //~ ERROR expected function () //~ ERROR expected `;`, found `}` } fn b() { let x = 5; let y = x //~ ERROR expected function (); } fn c() { let x = 5; x //~ ERROR expected function () } fn d() { // ok let x = || (); x () } fn e() { // ok let x = || (); x (); } fn f() { let y = 5 //~ ERROR expected function () //~ ERROR expected `;`, found `}` } fn g() { 5 //~ ERROR expected function (); } fn main() {} </ins>