Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Invalid error message for a line missing semicolon #80446

Closed
AMythicDev opened this issue Dec 28, 2020 · 1 comment · Fixed by #117292
Closed

Invalid error message for a line missing semicolon #80446

AMythicDev opened this issue Dec 28, 2020 · 1 comment · Fixed by #117292
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-parser Area: The parsing of Rust source code to an AST C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@AMythicDev
Copy link
Contributor

I tried this code:

           find(line.to_string(), &cap[0]).iter().for_each(|x| {
                #[allow(clippy::cast_possible_truncation)]
                coordinates.push((*x as u16, i as u16));  
            })

            *line = replace;

I expected to see this error happen: Missing semicolon at the end of statement
Instead, these two errors happened:

error[E0070]: invalid left-hand side of assignment
error[E0369]: cannot multiply `&mut String` to `()`

Meta

I ran this on both stable and nightly. Here are the versions

rustc 1.48.0 (7eac88abb 2020-11-16)
binary: rustc
commit-hash: 7eac88abb2e57e752f3302f02be5f3ce3d7adfb4
commit-date: 2020-11-16
host: x86_64-unknown-linux-gnu
release: 1.48.0
LLVM version: 11.0

rustc 1.50.0-nightly (fe982319a 2020-11-19)
binary: rustc
commit-hash: fe982319aa0aa5bbfc2795791a753832292bd2ba
commit-date: 2020-11-19
host: x86_64-unknown-linux-gnu
release: 1.50.0-nightly
Complete error

error[E0070]: invalid left-hand side of assignment
   --> src/search.rs:150:19
    |
145 | /             find(line.to_string(), &cap[0]).iter().for_each(|x| {
146 | |                 #[allow(clippy::cast_possible_truncation)]
147 | |                 coordinates.push((*x as u16, i as u16));
148 | |             })
149 | |
150 | |             *line = replace;
    | |                 - ^
    | |_________________|
    |                   cannot assign to this expression

error[E0369]: cannot multiply `&mut String` to `()`
   --> src/search.rs:150:13
    |
145 | /             find(line.to_string(), &cap[0]).iter().for_each(|x| {
146 | |                 #[allow(clippy::cast_possible_truncation)]
147 | |                 coordinates.push((*x as u16, i as u16));
148 | |             })
    | |______________- ()
149 |
150 |               *line = replace;
    |               ^---- &mut String

@AMythicDev AMythicDev added the C-bug Category: This is a bug. label Dec 28, 2020
@PatchMixolydic
Copy link
Contributor

PatchMixolydic commented Dec 28, 2020

I'm pretty sure rustc's lexer/parser discard all whitespace, including newlines, which unfortunately makes emitting a better diagnostic difficult, if not impossible.

Essentially, the parser sees this:

find(line.to_string(), &cap[0]).iter().for_each(...) * line = replace;

and reads it as an assignment to the result of a multiplication, which is why it issues these diagnostics. Unfortunately, this case is difficult to discern from cases where the diagnostics that rustc already emits would be correct:

fn main() {
    let x = 4;
    let y;
    // I wonder if Rust has a simple algebra solver...
    x * y = 8;
    assert_eq!(y, 2);
}
error[E0070]: invalid left-hand side of assignment
 --> src/main.rs:4:11
  |
4 |     x * y = 8;
  |     ----- ^
  |     |
  |     cannot assign to this expression

Whitespace probably cannot be made significant for multiplications at this point since that would likely cause a breaking change. There are probably codebases that do something like this:

let foobar = very.long(expressions, that).take(up, a, whole).bunch::<of, SPACE>()
    * very.long(expressions, that).take(up, a, whole).bunch::<of, SPACE>()
    * very.long(expressions, that).take(up, a, whole).bunch::<of, SPACE>()
    * very.long(expressions, that).take(up, a, whole).bunch::<of, SPACE>();

Since the left hand side of an assignment can be an arbitrarily long expression, discerning a multiplication broken across multiple lines from a statement with a missing semicolon followed by an assignment to a dereference would probably require the parser to look infinitely far ahead, which as far as I know is something that Rust actively avoids.

@jonas-schievink jonas-schievink added A-diagnostics Area: Messages for errors, warnings, and lints A-parser Area: The parsing of Rust source code to an AST C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. and removed C-bug Category: This is a bug. labels Dec 28, 2020
bors added a commit to rust-lang-ci/rust that referenced this issue Nov 6, 2023
Detect misparsed binop caused by missing semi

When encountering

```rust
foo()
*bar = baz;
```

We currently emit potentially two errors, one for the return type of
`foo` not being multiplicative by the type of `bar`, and another for
`foo() * bar` not being assignable.

We now check for this case and suggest adding a semicolon in the right
place and emit only a single error.

Fix rust-lang#80446.
@bors bors closed this as completed in 231f935 Nov 6, 2023
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-parser Area: The parsing of Rust source code to an AST C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants