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

Do not suggest importing hash_map::HashMap or btree_map::BTreeMap #72642

Closed
dtolnay opened this issue May 27, 2020 · 3 comments · Fixed by #73023
Closed

Do not suggest importing hash_map::HashMap or btree_map::BTreeMap #72642

dtolnay opened this issue May 27, 2020 · 3 comments · Fixed by #73023
Assignees
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-enhancement Category: An issue proposing an enhancement or a PR with one. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. D-verbose Diagnostics: Too much output caused by a single piece of incorrect code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@dtolnay
Copy link
Member

dtolnay commented May 27, 2020

struct S {
    m: HashMap<String, ()>,
}
error[E0412]: cannot find type `HashMap` in this scope
 --> src/main.rs:2:8
  |
2 |     m: HashMap<String, ()>,
  |        ^^^^^^^ not found in this scope
  |
help: consider importing one of these items
  |
1 | use std::collections::HashMap;
  |
1 | use std::collections::hash_map::HashMap;
  |

The std::collections::hash_map::HashMap suggestion here is just noise, it's (almost?) never what we actually want the person to import.

This issue has been assigned to @ayushmishra2005 via this comment.

@dtolnay dtolnay added C-enhancement Category: An issue proposing an enhancement or a PR with one. 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 May 27, 2020
@ayushmishra2005
Copy link
Contributor

@rustbot claim

@rustbot rustbot self-assigned this May 27, 2020
ayushmishra2005 pushed a commit to ayushmishra2005/rust that referenced this issue May 27, 2020
@estebank estebank added A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. D-verbose Diagnostics: Too much output caused by a single piece of incorrect code. labels May 28, 2020
@davidtwco
Copy link
Member

davidtwco commented Jun 2, 2020

@ayushmishra2005 responding to your comment here rather than on the PR - here are some rough pointers of what I'd look into (not having dug much into this myself, I can't say exactly what will be the solution):

So, let's start at the beginning - the suggestion that we see comes from this line:

let msg = format!("consider importing {} {}{}", determiner, kind, instead);

You can find that yourself using grep or just search on GitHub for the wording used in the suggestion (or some subset of it - as you can see, a bunch of this particular message is format strings). It looks like it gets the suggestions to print from a path_strings variable, which itself comes from the candidates argument.

That's in a function called show_candidates, searching for that - it's used once, here:

fn report_with_use_injections(&mut self, krate: &Crate) {
for UseError { mut err, candidates, def_id, better, suggestion } in
self.use_injections.drain(..)
{
let (span, found_use) = UsePlacementFinder::check(&self.definitions, krate, def_id);
if !candidates.is_empty() {
diagnostics::show_candidates(&mut err, span, &candidates, better, found_use);
} else if let Some((span, msg, sugg, appl)) = suggestion {
err.span_suggestion(span, msg, sugg, appl);
}
err.emit();
}
}

We can see that the candidates come from deconstructing a UseError struct. Fortunately, searching for UseError turns up only one location where it is constructed:

let report_errors = |this: &mut Self, res: Option<Res>| {
let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
let def_id = this.parent_scope.module.normal_ancestor_id;
let better = res.is_some();
let suggestion =
if res.is_none() { this.report_missing_type_error(path) } else { None };
this.r.use_injections.push(UseError { err, candidates, def_id, better, suggestion });
PartialRes::new(Res::Err)
};

Going even further back, we see that candidates is the result of calling smart_resolve_report_errors (defined here) - looking through that function, we can see that candidates is produced by calling lookup_import_candidates and then filtering the results (making sure that the suggestion isn't what we think the name already is and know to be incorrect):

let candidates = self
.r
.lookup_import_candidates(ident, ns, is_expected)
.drain(..)
.filter(|ImportSuggestion { did, .. }| {
match (did, res.and_then(|res| res.opt_def_id())) {
(Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
_ => true,
}
})
.collect::<Vec<_>>();

lookup_import_candidates (defined here) basically just calls lookup_import_candidates_from_module (defined here).

A rough read of this function suggests that it starts at some arbitrary starting module, looks over every name defined in that module for names that match what the user wrote, and if the current name is itself a module, it adds that to the list of modules to search.

I hope that you can see how this could start with something like std; and then look at std::collections, and std::fmt; and then std::collections::HashMap - and that matches the name that the user wrote, so it adds it as as candidate - and std::collections::HashSet - and that doesn't match the name, and so on; and then eventually std::collections::hash_map; before finding std::collections::hash_map::HashMap - which also matches the name that the user wrote! So we've ended up with two suggestions - it just also happens that they are suggesting the same thing - std::collections::HashMap is a re-export of std::collections::hash_map::HashMap.

I suspect that we could determine that both of these items are actually the same by comparing their DefIds - which this code finds just before adding the candidate:

let did = match res {
Res::Def(DefKind::Ctor(..), did) => this.parent(did),
_ => res.opt_def_id(),
};
candidates.push(ImportSuggestion { did, descr: res.descr(), path });

So what I'd probably end up doing is experimenting with how expensive it would be to iterate over each of the candidates before adding a new candidate (we know an error occurs at this point, so we've got some room to impact perf), and checking for duplicate suggestions; or maybe accumulating suggestions into a HashMap before converting to a Vec (using the DefId as a key, only replacing the value if the path would be shorter?).

edit: oh, and check out the rustc-dev-guide for getting your local environment set-up and as a reference.

@ayushmishra2005
Copy link
Contributor

@davidtwco Great Thanks. Let me work on it

ayushmishra2005 pushed a commit to ayushmishra2005/rust that referenced this issue Jun 3, 2020
Update src/librustc_resolve/diagnostics.rs

Co-authored-by: David Wood <[email protected]>

Minor refactoring rust-lang#72642

Fixed failing test-cases
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Jun 4, 2020
…tion, r=davidtwco

Remove noisy suggestion

Remove noisy suggestion rust-lang#72642
ayushmishra2005 pushed a commit to ayushmishra2005/rust that referenced this issue Jun 5, 2020
Update src/librustc_resolve/diagnostics.rs

Co-authored-by: David Wood <[email protected]>

Minor refactoring rust-lang#72642

Fixed failing test-cases

remove trivial `mk_predicate`s

Make `SourceMap` available for early debug-printing of `Span`s

Normally, we debug-print `Spans` using the `SourceMap` retrieved from
the global `TyCtxt`. However, we fall back to printing out the `Span`'s
raw fields (instead of a file and line number) when we try to print a
`Span` before a `TyCtxt` is available. This makes debugging early phases
of the compile, such as parsing, much more difficult.

This commit stores a `SourceMap` in `rustc_span::GlOBALS` as a fallback.
When a `TyCtxt` is not available, we try to retrieve one from `GLOBALS`
- only if this is not available do we fall back to the raw field output.

I'm not sure how to write a test for this - however, this can be
verified locally by setting `RUSTC_LOG="rustc_parse=debug"`, and
verifying that the output contains filenames and line numbers.

Add test for rust-lang#72554.

rustc_target: Remove `pre_link_args_crt`

Improve E0433, so that it suggests missing imports

Fix a typo in `late.rs`

Co-authored-by: Esteban Kuber <[email protected]>

fix `AdtDef` docs

Add Camelid

Email from @camelid:

> HI there,
>
> I’m a new contributor and I just looked at Rust Thanks and noticed that my contributions are listed under two different capitalizations of my name: “Camelid" and “camelid". Could you make them both “Camelid"?
>
> Thanks!
>
> Camelid

save_analysis: work on HIR tree instead of AST

Update `rls` submodule

remove outdated fixme

Hexagon libstd: fix typo for c_ulonglong

Add more assert to Vec with_capacity docs

Show assertion on len too to show them how adding new items will affect both the
length and capacity, before and after.

Add Kyle Strand to mailmap

Fix missing word in RELEASES.md

Update cargo

Enable lld for Cargo tests on Windows.

Fixed failing test-cases rust-lang#72642
ayushmishra2005 pushed a commit to ayushmishra2005/rust that referenced this issue Jun 5, 2020
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Jun 5, 2020
…tion, r=davidtwco

Remove noisy suggestion of hash_map

Remove noisy suggestion of hash_map rust-lang#72642

fixes rust-lang#72642
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Jun 5, 2020
…tion, r=davidtwco

Remove noisy suggestion of hash_map

Remove noisy suggestion of hash_map rust-lang#72642

fixes rust-lang#72642
ayushmishra2005 pushed a commit to ayushmishra2005/rust that referenced this issue Jun 9, 2020
Fixed failing test-cases

Remove noisy suggestion of hash_map rust-lang#72642

Fixed failing test-cases
@bors bors closed this as completed in e1cd8c4 Jun 11, 2020
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 A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-enhancement Category: An issue proposing an enhancement or a PR with one. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. D-verbose Diagnostics: Too much output caused by a single piece of incorrect code. 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.

5 participants