Skip to content

Commit f7202e4

Browse files
committed
Auto merge of #51456 - qmx:crate-in-path, r=nikomatsakis
resolve suggestions should use `crate::` when enabled I couldn't find a way to add a specific assertion for the ui test, so the expected output is living under the `crates-in-path.stderr` ui test. - is this the right place for the test? fixes #51212
2 parents 70a21e8 + d9791d6 commit f7202e4

File tree

6 files changed

+138
-22
lines changed

6 files changed

+138
-22
lines changed

src/librustc_resolve/lib.rs

+66-22
Original file line numberDiff line numberDiff line change
@@ -1952,9 +1952,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
19521952
"access to extern crates through prelude is experimental").emit();
19531953
}
19541954

1955-
let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span);
1956-
let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
1957-
self.populate_module_if_necessary(crate_root);
1955+
let crate_root = self.load_extern_prelude_crate_if_needed(ident);
19581956

19591957
let binding = (crate_root, ty::Visibility::Public,
19601958
ident.span, Mark::root()).to_name_binding(self.arenas);
@@ -1982,6 +1980,13 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
19821980
None
19831981
}
19841982

1983+
fn load_extern_prelude_crate_if_needed(&mut self, ident: Ident) -> Module<'a> {
1984+
let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span);
1985+
let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
1986+
self.populate_module_if_necessary(&crate_root);
1987+
crate_root
1988+
}
1989+
19851990
fn hygienic_lexical_parent(&mut self, module: Module<'a>, span: &mut Span)
19861991
-> Option<Module<'a>> {
19871992
if !module.expansion.is_descendant_of(span.ctxt().outer()) {
@@ -4228,24 +4233,20 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
42284233
}
42294234
}
42304235

4231-
/// When name resolution fails, this method can be used to look up candidate
4232-
/// entities with the expected name. It allows filtering them using the
4233-
/// supplied predicate (which should be used to only accept the types of
4234-
/// definitions expected e.g. traits). The lookup spans across all crates.
4235-
///
4236-
/// NOTE: The method does not look into imports, but this is not a problem,
4237-
/// since we report the definitions (thus, the de-aliased imports).
4238-
fn lookup_import_candidates<FilterFn>(&mut self,
4236+
fn lookup_import_candidates_from_module<FilterFn>(&mut self,
42394237
lookup_name: Name,
42404238
namespace: Namespace,
4239+
start_module: &'a ModuleData<'a>,
4240+
crate_name: Ident,
42414241
filter_fn: FilterFn)
42424242
-> Vec<ImportSuggestion>
42434243
where FilterFn: Fn(Def) -> bool
42444244
{
42454245
let mut candidates = Vec::new();
42464246
let mut worklist = Vec::new();
42474247
let mut seen_modules = FxHashSet();
4248-
worklist.push((self.graph_root, Vec::new(), false));
4248+
let not_local_module = crate_name != keywords::Crate.ident();
4249+
worklist.push((start_module, Vec::<ast::PathSegment>::new(), not_local_module));
42494250

42504251
while let Some((in_module,
42514252
path_segments,
@@ -4264,17 +4265,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
42644265
if ident.name == lookup_name && ns == namespace {
42654266
if filter_fn(name_binding.def()) {
42664267
// create the path
4267-
let mut segms = if self.session.rust_2018() && !in_module_is_extern {
4268+
let mut segms = path_segments.clone();
4269+
if self.session.rust_2018() {
42684270
// crate-local absolute paths start with `crate::` in edition 2018
42694271
// FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
4270-
let mut full_segms = vec![
4271-
ast::PathSegment::from_ident(keywords::Crate.ident())
4272-
];
4273-
full_segms.extend(path_segments.clone());
4274-
full_segms
4275-
} else {
4276-
path_segments.clone()
4277-
};
4272+
segms.insert(
4273+
0, ast::PathSegment::from_ident(crate_name)
4274+
);
4275+
}
42784276

42794277
segms.push(ast::PathSegment::from_ident(ident));
42804278
let path = Path {
@@ -4300,7 +4298,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
43004298
let mut path_segments = path_segments.clone();
43014299
path_segments.push(ast::PathSegment::from_ident(ident));
43024300

4303-
if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
4301+
let is_extern_crate_that_also_appears_in_prelude =
4302+
name_binding.is_extern_crate() &&
4303+
self.session.rust_2018();
4304+
4305+
let is_visible_to_user =
4306+
!in_module_is_extern || name_binding.vis == ty::Visibility::Public;
4307+
4308+
if !is_extern_crate_that_also_appears_in_prelude && is_visible_to_user {
43044309
// add the module to the lookup
43054310
let is_extern = in_module_is_extern || name_binding.is_extern_crate();
43064311
if seen_modules.insert(module.def_id().unwrap()) {
@@ -4314,6 +4319,45 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
43144319
candidates
43154320
}
43164321

4322+
/// When name resolution fails, this method can be used to look up candidate
4323+
/// entities with the expected name. It allows filtering them using the
4324+
/// supplied predicate (which should be used to only accept the types of
4325+
/// definitions expected e.g. traits). The lookup spans across all crates.
4326+
///
4327+
/// NOTE: The method does not look into imports, but this is not a problem,
4328+
/// since we report the definitions (thus, the de-aliased imports).
4329+
fn lookup_import_candidates<FilterFn>(&mut self,
4330+
lookup_name: Name,
4331+
namespace: Namespace,
4332+
filter_fn: FilterFn)
4333+
-> Vec<ImportSuggestion>
4334+
where FilterFn: Fn(Def) -> bool
4335+
{
4336+
let mut suggestions = vec![];
4337+
4338+
suggestions.extend(
4339+
self.lookup_import_candidates_from_module(
4340+
lookup_name, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn
4341+
)
4342+
);
4343+
4344+
if self.session.features_untracked().extern_prelude {
4345+
let extern_prelude_names = self.extern_prelude.clone();
4346+
for &krate_name in extern_prelude_names.iter() {
4347+
let krate_ident = Ident::with_empty_ctxt(krate_name);
4348+
let external_prelude_module = self.load_extern_prelude_crate_if_needed(krate_ident);
4349+
4350+
suggestions.extend(
4351+
self.lookup_import_candidates_from_module(
4352+
lookup_name, namespace, external_prelude_module, krate_ident, &filter_fn
4353+
)
4354+
);
4355+
}
4356+
}
4357+
4358+
suggestions
4359+
}
4360+
43174361
fn find_module(&mut self,
43184362
module_def: Def)
43194363
-> Option<(Module<'a>, ImportSuggestion)>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-include ../tools.mk
2+
3+
all:
4+
$(RUSTC) ep-nested-lib.rs
5+
6+
$(RUSTC) use-suggestions.rs --edition=2018 --extern ep_nested_lib=$(TMPDIR)/libep_nested_lib.rlib 2>&1 | $(CGREP) "use ep_nested_lib::foo::bar::Baz"
7+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_type = "rlib"]
12+
13+
pub mod foo {
14+
pub mod bar {
15+
pub struct Baz;
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let x = Baz{};
13+
}

src/test/ui/crate-in-paths.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// edition:2018
12+
13+
#![feature(edition_2018_preview)]
14+
15+
mod bar {
16+
crate struct Foo;
17+
}
18+
19+
fn main() {
20+
Foo;
21+
//~^ ERROR cannot find value `Foo` in this scope [E0425]
22+
}

src/test/ui/crate-in-paths.stderr

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0425]: cannot find value `Foo` in this scope
2+
--> $DIR/crate-in-paths.rs:20:5
3+
|
4+
LL | Foo;
5+
| ^^^ not found in this scope
6+
help: possible candidate is found in another module, you can import it into scope
7+
|
8+
LL | use crate::bar::Foo;
9+
|
10+
11+
error: aborting due to previous error
12+
13+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)