Skip to content

Conversation

davidtwco
Copy link
Member

Fixes #54230.

This commit adds suggestions for unresolved imports in the cases where
there could be a missing crate::, super::, self:: or a missing
external crate name before an import.

r? @nikomatsakis

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 20, 2018
@davidtwco davidtwco force-pushed the issue-54230 branch 2 times, most recently from 6abb101 to 317163a Compare September 20, 2018 15:16
Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, nice!

@nikomatsakis
Copy link
Contributor

The code looks pretty good to me. I think there are some policy questions, e.g. the way that it prefers self or super to crate, that are not entirely clear to me. But probably not a big deal in practice.

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Sep 21, 2018

Or, I guess that the current heuristic is:

  • self::foo
  • crate::foo
  • super::bar
  • extern_crate::bar

It feels like it might be reasonable to show more than one, too, though it'd be silly to do so if they are the same thing underneath.

@davidtwco
Copy link
Member Author

The code looks pretty good to me. I think there are some policy questions, e.g. the way that it prefers self or super to crate, that are not entirely clear to me. But probably not a big deal in practice.

Yeah, I've ordered these entirely arbitrarily - we can adjust that. I also experimented with having it attempt to correct misspellings but I couldn't quite tweak it so it wasn't over- or under-correcting. I would get it so if I had tsd::path it would suggest std::path but it would also suggest that for things that were completely wrong; and on the other end of the scale, if I had a long path that had one or two characters swapped, it wouldn't suggest anything.

@nikomatsakis
Copy link
Contributor

I'm feeling a bit confused now because I know there is also this lookup_import_candidates_from_module function, and I'm trying to figure out how/if these ought to relate to one another. =)

@nikomatsakis
Copy link
Contributor

Maybe that code is only invoked if the bar part of foo::bar fails, not the foo part?

@eddyb
Copy link
Member

eddyb commented Sep 21, 2018

r? @eddyb

@rust-highfive rust-highfive assigned eddyb and unassigned nikomatsakis Sep 21, 2018
@davidtwco
Copy link
Member Author

davidtwco commented Sep 21, 2018

@nikomatsakis If it is at all helpful, these are the rough notes I threw together when initially working out what was happening and where these errors were coming from:

Searching for the error message, we find it in resolve_path_with_scope:

let msg = if module_def == self.graph_root.def() {
let is_mod = |def| match def { Def::Mod(..) => true, _ => false };
let mut candidates =
self.lookup_import_candidates(name, TypeNS, is_mod);
candidates.sort_by_cached_key(|c| {
(c.path.segments.len(), c.path.to_string())
});
if let Some(candidate) = candidates.get(0) {
format!("Did you mean `{}`?", candidate.path)
} else {
format!("Maybe a missing `extern crate {};`?", ident)
}
} else if i == 0 {
format!("Use of undeclared type or module `{}`", ident)
} else {
format!("Could not find `{}` in `{}`", ident, path[i - 1])
};

This returns a PathResult::Failed(..) with a span, message and boolean indicating if this is the last error. resolve_path_with_parent_scope is called by resolve_path.

resolved_path is called by resolve_import where the PathResult is matched, returning true:

match result {
PathResult::Module(module) => module,
PathResult::Indeterminate => return false,
_ => return true,
}

resolve_import is called by resolved_imports where the true is matched against to add the import that failed to the determined_imports list:

match self.resolve_import(&import) {
true => self.determined_imports.push(import),
false => self.indeterminate_imports.push(import),
}

Later, finalize_imports is called, this iterates over the determined_imports which calls finalize_import:

for i in 0 .. self.determined_imports.len() {
let import = self.determined_imports[i];
let error = self.finalize_import(import);

finalize_import eventually returns a span and a message, this is where we can see the original self:: suggestion being made:

let (mut self_path, mut self_result) = (module_path.clone(), None);
let is_special = |ident: Ident| ident.is_path_segment_keyword() &&
ident.name != keywords::CrateRoot.name();
if !self_path.is_empty() && !is_special(self_path[0]) &&
!(self_path.len() > 1 && is_special(self_path[1])) {
self_path[0].name = keywords::SelfValue.name();
self_result = Some(self.resolve_path(None, &self_path, None, false,
span, CrateLint::No));
}
return if let Some(PathResult::Module(..)) = self_result {
Some((span, format!("Did you mean `{}`?", names_to_string(&self_path[..]))))
} else {
Some((span, msg))
};

This then goes back to finalize_imports which calls adds the span and message to a vector:

error_vec.push((span, path, err));

That vector then is passed to throw_unresolved_import_error:

self.throw_unresolved_import_error(error_vec.clone(), None);

throw_unresolved_import_error throws the actual error that we see:

fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>,

@XAMPPRocky XAMPPRocky added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 26, 2018
@davidtwco davidtwco changed the title WIP: suggest crate::... for "local" paths in 2018 suggest crate::... for "local" paths in 2018 Sep 27, 2018

for name in &external_crate_names {
// Don't suggest meta as it will error in `resolve_path`.
if name.as_str() == "meta" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoding this is wrong - you want to use something like this instead:

if self.session.rust_2018() {
let extern_prelude_names = self.extern_prelude.clone();
for &name in extern_prelude_names.iter() {
let ident = Ident::with_empty_ctxt(name);
match self.crate_loader.maybe_process_path_extern(name, ident.span) {

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated this.

@eddyb
Copy link
Member

eddyb commented Sep 28, 2018

I think this PR might need to check the edition? Or somehow involve the compat lints.
That said,
r? @petrochenkov

@rust-highfive rust-highfive assigned petrochenkov and unassigned eddyb Sep 28, 2018
@davidtwco
Copy link
Member Author

@eddyb I've added a test demonstrating the 2015 behaviour for the same test case.

@petrochenkov
Copy link
Contributor

@bors r+

@bors
Copy link
Collaborator

bors commented Oct 2, 2018

📌 Commit 1525e97 has been approved by petrochenkov

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 2, 2018
pietroalbini added a commit to pietroalbini/rust that referenced this pull request Oct 2, 2018
suggest `crate::...` for "local" paths in 2018

Fixes rust-lang#54230.

This commit adds suggestions for unresolved imports in the cases where
there could be a missing `crate::`, `super::`, `self::` or a missing
external crate name before an import.

r? @nikomatsakis
@bors

This comment has been minimized.

@kennytm kennytm removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 3, 2018
@davidtwco

This comment has been minimized.

@bors

This comment has been minimized.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 3, 2018
@bors

This comment has been minimized.

@bors

This comment has been minimized.

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Oct 3, 2018
@rust-highfive

This comment has been minimized.

This commit adds suggestions for unresolved imports in the cases where
there could be a missing `crate::`, `super::`, `self::` or a missing
external crate name before an import.
Previously, `meta` crate was hardcoded as attempting to resolve a path
with it would ICE. Now, we attempt to load each extern crate first so
that resolving a path involving that crate doesn't error.
Adds a test to demonstrate behaviour of suggestions in the
2015 edition.
This commit ensures that the external crate suggestion is deterministic
by using a `BTreeMap` rather than a `FxHashMap`. This is particularly
useful as `std` and `core` will often contain the same items and
therefore the suggestion would previously suggest either for any given
error - in this case, the suggestion will always prefer `std` now.
@davidtwco
Copy link
Member Author

@bors r=petrochenkov

@bors
Copy link
Collaborator

bors commented Oct 3, 2018

📌 Commit 5872d3e has been approved by petrochenkov

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 3, 2018
@bors
Copy link
Collaborator

bors commented Oct 3, 2018

⌛ Testing commit 5872d3e with merge 4bf883b...

bors added a commit that referenced this pull request Oct 3, 2018
suggest `crate::...` for "local" paths in 2018

Fixes #54230.

This commit adds suggestions for unresolved imports in the cases where
there could be a missing `crate::`, `super::`, `self::` or a missing
external crate name before an import.

r? @nikomatsakis
@bors
Copy link
Collaborator

bors commented Oct 4, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: petrochenkov
Pushing 4bf883b to master...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

suggest crate::... for "local" paths in 2018
8 participants