Skip to content

Commit d5da94a

Browse files
committed
rustc_resolve: ignore uniform_paths canaries that resolve to an import of the same crate.
1 parent 0a33de0 commit d5da94a

File tree

4 files changed

+72
-43
lines changed

4 files changed

+72
-43
lines changed

src/librustc_resolve/build_reduced_graph.rs

+1-17
Original file line numberDiff line numberDiff line change
@@ -199,22 +199,6 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
199199
if emit_uniform_paths_canary {
200200
let source = prefix_start.unwrap();
201201

202-
// HACK(eddyb) For `use x::{self, ...};`, use the ID of the
203-
// `self` nested import for the canary. This allows the
204-
// ambiguity reporting scope to ignore false positives
205-
// in the same way it does for `use x;` (by comparing IDs).
206-
let mut canary_id = id;
207-
if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
208-
for &(ref use_tree, id) in items {
209-
if let ast::UseTreeKind::Simple(..) = use_tree.kind {
210-
if use_tree.ident().name == keywords::SelfValue.name() {
211-
canary_id = id;
212-
break;
213-
}
214-
}
215-
}
216-
}
217-
218202
// Helper closure to emit a canary with the given base path.
219203
let emit = |this: &mut Self, base: Option<Ident>| {
220204
let subclass = SingleImport {
@@ -234,7 +218,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
234218
base.into_iter().collect(),
235219
subclass.clone(),
236220
source.span,
237-
canary_id,
221+
id,
238222
root_use_tree.span,
239223
root_id,
240224
ty::Visibility::Invisible,

src/librustc_resolve/resolve_imports.rs

+38-26
Original file line numberDiff line numberDiff line change
@@ -620,9 +620,9 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
620620
}
621621

622622
#[derive(Default)]
623-
struct UniformPathsCanaryResult {
624-
module_scope: Option<Span>,
625-
block_scopes: Vec<Span>,
623+
struct UniformPathsCanaryResult<'a> {
624+
module_scope: Option<&'a NameBinding<'a>>,
625+
block_scopes: Vec<&'a NameBinding<'a>>,
626626
}
627627
// Collect all tripped `uniform_paths` canaries separately.
628628
let mut uniform_paths_canaries: BTreeMap<
@@ -661,20 +661,12 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
661661

662662
self.per_ns(|_, ns| {
663663
if let Some(result) = result[ns].get().ok() {
664-
if let NameBindingKind::Import { directive, .. } = result.kind {
665-
// Skip canaries that resolve to the import itself.
666-
// These come from `use crate_name;`, which isn't really
667-
// ambiguous, as the import can't actually shadow itself.
668-
if directive.id == import.id {
669-
return;
670-
}
671-
}
672664
if has_explicit_self {
673665
// There should only be one `self::x` (module-scoped) canary.
674-
assert_eq!(canary_results[ns].module_scope, None);
675-
canary_results[ns].module_scope = Some(result.span);
666+
assert!(canary_results[ns].module_scope.is_none());
667+
canary_results[ns].module_scope = Some(result);
676668
} else {
677-
canary_results[ns].block_scopes.push(result.span);
669+
canary_results[ns].block_scopes.push(result);
678670
}
679671
}
680672
});
@@ -708,16 +700,36 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
708700
let uniform_paths_feature = self.session.features_untracked().uniform_paths;
709701
for ((span, _), (name, results)) in uniform_paths_canaries {
710702
self.per_ns(|this, ns| {
711-
let results = &results[ns];
703+
let external_crate = if ns == TypeNS && this.extern_prelude.contains(&name) {
704+
let crate_id =
705+
this.crate_loader.process_path_extern(name, span);
706+
Some(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
707+
} else {
708+
None
709+
};
710+
let result_filter = |result: &&NameBinding| {
711+
// Ignore canaries that resolve to an import of the same crate.
712+
// That is, we allow `use crate_name; use crate_name::foo;`.
713+
if let Some(def_id) = external_crate {
714+
if let Some(module) = result.module() {
715+
if module.normal_ancestor_id == def_id {
716+
return false;
717+
}
718+
}
719+
}
712720

713-
let has_external_crate =
714-
ns == TypeNS && this.extern_prelude.contains(&name);
721+
true
722+
};
723+
let module_scope = results[ns].module_scope.filter(result_filter);
724+
let block_scopes = || {
725+
results[ns].block_scopes.iter().cloned().filter(result_filter)
726+
};
715727

716728
// An ambiguity requires more than one possible resolution.
717729
let possible_resultions =
718-
(has_external_crate as usize) +
719-
(results.module_scope.is_some() as usize) +
720-
(!results.block_scopes.is_empty() as usize);
730+
(external_crate.is_some() as usize) +
731+
(module_scope.is_some() as usize) +
732+
(block_scopes().next().is_some() as usize);
721733
if possible_resultions <= 1 {
722734
return;
723735
}
@@ -727,26 +739,26 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
727739
let msg = format!("`{}` import is ambiguous", name);
728740
let mut err = this.session.struct_span_err(span, &msg);
729741
let mut suggestion_choices = String::new();
730-
if has_external_crate {
742+
if external_crate.is_some() {
731743
write!(suggestion_choices, "`::{}`", name);
732744
err.span_label(span,
733745
format!("can refer to external crate `::{}`", name));
734746
}
735-
if let Some(span) = results.module_scope {
747+
if let Some(result) = module_scope {
736748
if !suggestion_choices.is_empty() {
737749
suggestion_choices.push_str(" or ");
738750
}
739751
write!(suggestion_choices, "`self::{}`", name);
740752
if uniform_paths_feature {
741-
err.span_label(span,
753+
err.span_label(result.span,
742754
format!("can refer to `self::{}`", name));
743755
} else {
744-
err.span_label(span,
756+
err.span_label(result.span,
745757
format!("may refer to `self::{}` in the future", name));
746758
}
747759
}
748-
for &span in &results.block_scopes {
749-
err.span_label(span,
760+
for result in block_scopes() {
761+
err.span_label(result.span,
750762
format!("shadowed by block-scoped `{}`", name));
751763
}
752764
err.help(&format!("write {} explicitly instead", suggestion_choices));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
// run-pass
12+
// edition:2018
13+
14+
use std;
15+
use std::io;
16+
17+
mod foo {
18+
pub use std as my_std;
19+
}
20+
21+
mod bar {
22+
pub use std::{self};
23+
}
24+
25+
fn main() {
26+
io::stdout();
27+
self::std::io::stdout();
28+
foo::my_std::io::stdout();
29+
bar::std::io::stdout();
30+
}

src/test/run-pass/redundant.rs src/test/ui/rust-2018/uniform-paths/redundant.rs

+3
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// run-pass
1112
// edition:2018
1213

1314
#![feature(uniform_paths)]
1415

1516
use std;
17+
use std::io;
1618

1719
mod foo {
1820
pub use std as my_std;
@@ -23,6 +25,7 @@ mod bar {
2325
}
2426

2527
fn main() {
28+
io::stdout();
2629
self::std::io::stdout();
2730
foo::my_std::io::stdout();
2831
bar::std::io::stdout();

0 commit comments

Comments
 (0)