Change:
UPDATE: There has been some progress on this issue. prefixes now work, but you still don't get suggestions from other crates except when you write an explicit . When you get name resolution suggestions from resolve after an error, they should use prefixes where appropriate. Example (): gives but I want to see suggested.
It looks like the suggestions are issued here: The behavior I think we want is this: The function that prepares those suggestions appears to be this one: Here is an example of checking for whether the feature is enabled:
expressed some interest in tackling this.
Hmm, now i'm worried that this will apply even when it shouldn't. Consider this testcase: This currently prints: and I think we do not want it to print . I think this suggests an alternative fix to what I recommended before (and what did in ) -- but I'd like to get opinion. Before I suggested changing how the values are printed out, but now I think we should change them at the source: Right now, this works by walking through the crate and finding candidates. I suspect (but we should test) that this means it will not work when the option is enabled and no explicit exists, because there is nothing to walk over. Therefore, the change I propose is as follows: the function to (if is enabled) to push a at the front of the import suggestions it is currently creating. This is because all of them are found by trawling the crate source. , if is enabled, add a loop that executes first. This would go over all of the crates that are available from the command line, load them up, and search for the item within (basically the same as the existing search, but beginning from the crate directly). In this case, we would not prepend to the resulting path, but instead the name of the crate we are searching. One flaw I can see here is that it may be that the crate is locally shadowed. I suspect we can overlook that possibility for now.
do the above notes seem ok?
Looks reasonable.
To get a bit more detailed in how to make this modification, ultimately I envision we'll have a helper like this: This will be roughly the same as the existing , except that instead of starting from , it will seed the worklist with : Then, later, when it finds a suggestion: It will check if and the feature is enabled. In that case, it adds to the start of the suggestion. This is step 1. Step 2 in a second. =)
OK, so step 2... The basic idea was to iterate over each of the "available" crates. For each crate, we would load the crate (if not already loaded), and then use the fn to walk and make a suggestion. So the first question is where we find that list of available crates and how to load it. Here are some pointers. For example, here is where we find the set of things in the prelude: which ends up in the Resolver struct. And this is where we resolve paths that rely on external prelude: It seems sort of like this is the snippet of code to "load a crate if needed": I think the idea would be to refactor that last snippet of code into a helper fn, and then invoke it from . So would look something like: OK, there is a slight flaw -- I think that should take not a ("in root") but rather a with the crate name to prepend (which would be in the case of the root module). I've modified the code above accordingly.

Discussion:
"access to extern crates through prelude is experimental").emit(); } <del> let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span); let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); self.populate_module_if_necessary(crate_root); </del> <ins> let crate_root = self.load_extern_prelude_crate_if_needed(ident); </ins> let binding = (crate_root, ty::Visibility::Public, ident.span, Mark::root()).to_name_binding(self.arenas);

None } <ins> fn load_extern_prelude_crate_if_needed(&mut self, ident: Ident) -> Module<'a> { let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span); let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); self.populate_module_if_necessary(&crate_root); crate_root } </ins> fn hygienic_lexical_parent(&mut self, module: Module<'a>, span: &mut Span) -> Option<Module<'a>> { if !module.expansion.is_descendant_of(span.ctxt().outer()) {

} } <del> /// When name resolution fails, this method can be used to look up candidate /// entities with the expected name. It allows filtering them using the /// supplied predicate (which should be used to only accept the types of /// definitions expected e.g. traits). The lookup spans across all crates. /// /// NOTE: The method does not look into imports, but this is not a problem, /// since we report the definitions (thus, the de-aliased imports). fn lookup_import_candidates<FilterFn>(&mut self, </del> <ins> fn lookup_import_candidates_from_module<FilterFn>(&mut self, </ins> lookup_name: Name, namespace: Namespace, <ins> start_module: &'a ModuleData<'a>, graph_root: bool, </ins> filter_fn: FilterFn) -> Vec<ImportSuggestion> where FilterFn: Fn(Def) -> bool

let mut candidates = Vec::new(); let mut worklist = Vec::new(); let mut seen_modules = FxHashSet(); <del> worklist.push((self.graph_root, Vec::new(), false)); </del> <ins> worklist.push((start_module, Vec::new(), false)); </ins> while let Some((in_module, path_segments,

if ident.name == lookup_name && ns == namespace { if filter_fn(name_binding.def()) { // create the path <del> let mut segms = if self.session.rust_2018() && !in_module_is_extern { </del> <ins> let mut segms = path_segments.clone(); if self.session.rust_2018() && !in_module_is_extern { </ins> // crate-local absolute paths start with `crate::` in edition 2018 // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660) <del> let mut full_segms = vec![ ast::PathSegment::from_ident(keywords::Crate.ident()) ]; full_segms.extend(path_segments.clone()); full_segms } else { path_segments.clone() }; </del> <ins> if graph_root { segms.insert( 0, ast::PathSegment::from_ident(keywords::Crate.ident()) ); } } </ins> segms.push(ast::PathSegment::from_ident(ident)); let path = Path {

candidates } <ins> /// When name resolution fails, this method can be used to look up candidate /// entities with the expected name. It allows filtering them using the /// supplied predicate (which should be used to only accept the types of /// definitions expected e.g. traits). The lookup spans across all crates. /// /// NOTE: The method does not look into imports, but this is not a problem, /// since we report the definitions (thus, the de-aliased imports). fn lookup_import_candidates<FilterFn>(&mut self, lookup_name: Name, namespace: Namespace, filter_fn: FilterFn) -> Vec<ImportSuggestion> where FilterFn: Fn(Def) -> bool { self.lookup_import_candidates_from_module( lookup_name, namespace, self.graph_root, true, filter_fn ) } </ins> fn find_module(&mut self, module_def: Def) -> Option<(Module<'a>, ImportSuggestion)>

<ins> // Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. // edition:2018 #![feature(edition_2018_preview)] mod bar { crate struct Foo; } fn main() { Foo; //~^ ERROR cannot find value `Foo` in this scope [E0425] } </ins>

<ins> error[E0425]: cannot find value `Foo` in this scope --> $DIR/crate-in-paths.rs:20:5 | LL |     Foo; |     ^^^ not found in this scope help: possible candidate is found in another module, you can import it into scope | LL | use crate::bar::Foo; | error: aborting due to previous error For more information about this error, try `rustc --explain E0425`. </ins>