Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Using flat_map on an Option<T> should suggest using and_then instead #108437

Closed
liquidev opened this issue Feb 24, 2023 · 2 comments · Fixed by #120730
Closed

Using flat_map on an Option<T> should suggest using and_then instead #108437

liquidev opened this issue Feb 24, 2023 · 2 comments · Fixed by #120730
Labels
A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@liquidev
Copy link

liquidev commented Feb 24, 2023

Code

fn main() {
    let opt = Some(1);
    opt.flat_map(|val| Some(val));
}

Current output

error[E0599]: `Option<{integer}>` is not an iterator
 --> src/main.rs:3:9
  |
3 |     opt.flat_map(|val| Some(val));
  |         ^^^^^^^^ `Option<{integer}>` is not an iterator
 --> /rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/option.rs:518:1
  |
  = note: doesn't satisfy `Option<{integer}>: Iterator`
  |
  = note: the following trait bounds were not satisfied:
          `Option<{integer}>: Iterator`
          which is required by `&mut Option<{integer}>: Iterator`

For more information about this error, try `rustc --explain E0599`.
error: could not compile `playground` due to previous error

Desired output

error[E0599]: `Option<{integer}>` is not an iterator
 --> src/main.rs:3:9
  |
3 |     opt.flat_map(|val| Some(val));
  |         ^^^^^^^^
  |         | `Option<{integer}>` is not an iterator
  |         = help: if you wish to map and flatten the option, use `and_then`
 --> /rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/option.rs:518:1
  |
  = note: doesn't satisfy `Option<{integer}>: Iterator`
  |
  = note: the following trait bounds were not satisfied:
          `Option<{integer}>: Iterator`
          which is required by `&mut Option<{integer}>: Iterator`

For more information about this error, try `rustc --explain E0599`.
error: could not compile `playground` due to previous error

Rationale and extra context

I've run into this confusing naming issue time and time again and I think the compiler could provide a more helpful error message in this case, hinting that you should use and_then instead of flat_map if you wish to do the same operation on options (which you could write as .map().flatten(), hence why I always think it's Option::flat_map and not Option::and_then.)

Other cases

No response

Anything else?

No response

@liquidev liquidev added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Feb 24, 2023
@fmease
Copy link
Member

fmease commented Feb 24, 2023

#59450 related

bors added a commit to rust-lang-ci/rust that referenced this issue Jul 16, 2023
…ons, r=cjgillot

Add `#[rustc_confusables]` attribute to allow targeted "no method" error suggestions on standard library types

After this PR, the standard library developer can annotate methods on e.g. `BTreeSet::push` with `#[rustc_confusables("insert")]`. When the user mistypes `btreeset.push()`, `BTreeSet::insert` will be suggested if there are no other candidates to suggest. This PR lays the foundations for contributors to add `rustc_confusables` annotations to standard library types for targeted suggestions, as specified in rust-lang#59450, or to address cases such as rust-lang#108437.

### Example

Assume `BTreeSet` is the standard library type:

```
// Standard library definition
#![feature(rustc_attrs)]

struct BTreeSet;

impl BTreeSet {
    #[rustc_confusables("push")]
    fn insert(&self) {}
}

// User code
fn main() {
    let x = BTreeSet {};
    x.push();
}
```

A new suggestion (which has lower precedence than suggestions for misspellings and only is shown when there are no misspellings suggestions) will be added to hint the user maybe they intended to write `x.insert()` instead:

```
error[E0599]: no method named `push` found for struct `BTreeSet` in the current scope
  --> test.rs:12:7
   |
3  | struct BTreeSet;
   | --------------- method `push` not found for this struct
...
12 |     x.push();
   |       ^^^^ method not found in `BTreeSet`
   |
help: you might have meant to use `insert`
   |
12 |     x.insert();
   |       ~~~~~~

error: aborting due to previous error
```
@jieyouxu
Copy link
Member

jieyouxu commented Feb 1, 2024

FWIW, since PR #112239 is merged, it should be quite easy to add this suggestion by marking and_then with #[rustc_confusables("flat_map")], along with a test.

oli-obk added a commit to oli-obk/rust that referenced this issue Feb 15, 2024
Provide suggestions through `rustc_confusables` annotations

Help with common API confusion, like asking for `push` when the data structure really has `append`.

```
error[E0599]: no method named `size` found for struct `Vec<{integer}>` in the current scope
  --> $DIR/rustc_confusables_std_cases.rs:17:7
   |
LL |     x.size();
   |       ^^^^
   |
help: you might have meant to use `len`
   |
LL |     x.len();
   |       ~~~
help: there is a method with a similar name
   |
LL |     x.resize();
   |       ~~~~~~
```

Fix rust-lang#59450 (we can open subsequent tickets for specific cases).

Fix rust-lang#108437:

```
error[E0599]: `Option<{integer}>` is not an iterator
   --> f101.rs:3:9
    |
3   |     opt.flat_map(|val| Some(val));
    |         ^^^^^^^^ `Option<{integer}>` is not an iterator
    |
   ::: /home/gh-estebank/rust/library/core/src/option.rs:571:1
    |
571 | pub enum Option<T> {
    | ------------------ doesn't satisfy `Option<{integer}>: Iterator`
    |
    = note: the following trait bounds were not satisfied:
            `Option<{integer}>: Iterator`
            which is required by `&mut Option<{integer}>: Iterator`
help: you might have meant to use `and_then`
    |
3   |     opt.and_then(|val| Some(val));
    |         ~~~~~~~~
```

On type error of method call arguments, look at confusables for suggestion. Fix rust-lang#87212:

```
error[E0308]: mismatched types
    --> f101.rs:8:18
     |
8    |     stuff.append(Thing);
     |           ------ ^^^^^ expected `&mut Vec<Thing>`, found `Thing`
     |           |
     |           arguments to this method are incorrect
     |
     = note: expected mutable reference `&mut Vec<Thing>`
                           found struct `Thing`
note: method defined here
    --> /home/gh-estebank/rust/library/alloc/src/vec/mod.rs:2025:12
     |
2025 |     pub fn append(&mut self, other: &mut Self) {
     |            ^^^^^^
help: you might have meant to use `push`
     |
8    |     stuff.push(Thing);
     |           ~~~~
```
bors added a commit to rust-lang-ci/rust that referenced this issue Feb 17, 2024
Provide suggestions through `rustc_confusables` annotations

Help with common API confusion, like asking for `push` when the data structure really has `append`.

```
error[E0599]: no method named `size` found for struct `Vec<{integer}>` in the current scope
  --> $DIR/rustc_confusables_std_cases.rs:17:7
   |
LL |     x.size();
   |       ^^^^
   |
help: you might have meant to use `len`
   |
LL |     x.len();
   |       ~~~
help: there is a method with a similar name
   |
LL |     x.resize();
   |       ~~~~~~
```

Fix rust-lang#59450 (we can open subsequent tickets for specific cases).

Fix rust-lang#108437:

```
error[E0599]: `Option<{integer}>` is not an iterator
   --> f101.rs:3:9
    |
3   |     opt.flat_map(|val| Some(val));
    |         ^^^^^^^^ `Option<{integer}>` is not an iterator
    |
   ::: /home/gh-estebank/rust/library/core/src/option.rs:571:1
    |
571 | pub enum Option<T> {
    | ------------------ doesn't satisfy `Option<{integer}>: Iterator`
    |
    = note: the following trait bounds were not satisfied:
            `Option<{integer}>: Iterator`
            which is required by `&mut Option<{integer}>: Iterator`
help: you might have meant to use `and_then`
    |
3   |     opt.and_then(|val| Some(val));
    |         ~~~~~~~~
```

On type error of method call arguments, look at confusables for suggestion. Fix rust-lang#87212:

```
error[E0308]: mismatched types
    --> f101.rs:8:18
     |
8    |     stuff.append(Thing);
     |           ------ ^^^^^ expected `&mut Vec<Thing>`, found `Thing`
     |           |
     |           arguments to this method are incorrect
     |
     = note: expected mutable reference `&mut Vec<Thing>`
                           found struct `Thing`
note: method defined here
    --> /home/gh-estebank/rust/library/alloc/src/vec/mod.rs:2025:12
     |
2025 |     pub fn append(&mut self, other: &mut Self) {
     |            ^^^^^^
help: you might have meant to use `push`
     |
8    |     stuff.push(Thing);
     |           ~~~~
```
@bors bors closed this as completed in a28d221 Feb 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints 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