if emit_uniform_paths_canary {
let source = prefix_start.unwrap();
- // HACK(eddyb) For `use x::{self, ...};`, use the ID of the
- // `self` nested import for the canary. This allows the
- // ambiguity reporting scope to ignore false positives
- // in the same way it does for `use x;` (by comparing IDs).
- let mut canary_id = id;
- if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
- for &(ref use_tree, id) in items {
- if let ast::UseTreeKind::Simple(..) = use_tree.kind {
- if use_tree.ident().name == keywords::SelfValue.name() {
- canary_id = id;
- break;
- }
- }
- }
- }
-
// Helper closure to emit a canary with the given base path.
let emit = |this: &mut Self, base: Option<Ident>| {
let subclass = SingleImport {
base.into_iter().collect(),
subclass.clone(),
source.span,
- canary_id,
+ id,
root_use_tree.span,
root_id,
ty::Visibility::Invisible,
}
#[derive(Default)]
- struct UniformPathsCanaryResult {
- module_scope: Option<Span>,
- block_scopes: Vec<Span>,
+ struct UniformPathsCanaryResult<'a> {
+ module_scope: Option<&'a NameBinding<'a>>,
+ block_scopes: Vec<&'a NameBinding<'a>>,
}
// Collect all tripped `uniform_paths` canaries separately.
let mut uniform_paths_canaries: BTreeMap<
self.per_ns(|_, ns| {
if let Some(result) = result[ns].get().ok() {
- if let NameBindingKind::Import { directive, .. } = result.kind {
- // Skip canaries that resolve to the import itself.
- // These come from `use crate_name;`, which isn't really
- // ambiguous, as the import can't actually shadow itself.
- if directive.id == import.id {
- return;
- }
- }
if has_explicit_self {
// There should only be one `self::x` (module-scoped) canary.
- assert_eq!(canary_results[ns].module_scope, None);
- canary_results[ns].module_scope = Some(result.span);
+ assert!(canary_results[ns].module_scope.is_none());
+ canary_results[ns].module_scope = Some(result);
} else {
- canary_results[ns].block_scopes.push(result.span);
+ canary_results[ns].block_scopes.push(result);
}
}
});
let uniform_paths_feature = self.session.features_untracked().uniform_paths;
for ((span, _), (name, results)) in uniform_paths_canaries {
self.per_ns(|this, ns| {
- let results = &results[ns];
+ let external_crate = if ns == TypeNS && this.extern_prelude.contains(&name) {
+ let crate_id =
+ this.crate_loader.process_path_extern(name, span);
+ Some(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
+ } else {
+ None
+ };
+ let result_filter = |result: &&NameBinding| {
+ // Ignore canaries that resolve to an import of the same crate.
+ // That is, we allow `use crate_name; use crate_name::foo;`.
+ if let Some(def_id) = external_crate {
+ if let Some(module) = result.module() {
+ if module.normal_ancestor_id == def_id {
+ return false;
+ }
+ }
+ }
- let has_external_crate =
- ns == TypeNS && this.extern_prelude.contains(&name);
+ true
+ };
+ let module_scope = results[ns].module_scope.filter(result_filter);
+ let block_scopes = || {
+ results[ns].block_scopes.iter().cloned().filter(result_filter)
+ };
// An ambiguity requires more than one possible resolution.
let possible_resultions =
- (has_external_crate as usize) +
- (results.module_scope.is_some() as usize) +
- (!results.block_scopes.is_empty() as usize);
+ (external_crate.is_some() as usize) +
+ (module_scope.is_some() as usize) +
+ (block_scopes().next().is_some() as usize);
if possible_resultions <= 1 {
return;
}
let msg = format!("`{}` import is ambiguous", name);
let mut err = this.session.struct_span_err(span, &msg);
let mut suggestion_choices = String::new();
- if has_external_crate {
+ if external_crate.is_some() {
write!(suggestion_choices, "`::{}`", name);
err.span_label(span,
format!("can refer to external crate `::{}`", name));
}
- if let Some(span) = results.module_scope {
+ if let Some(result) = module_scope {
if !suggestion_choices.is_empty() {
suggestion_choices.push_str(" or ");
}
write!(suggestion_choices, "`self::{}`", name);
if uniform_paths_feature {
- err.span_label(span,
+ err.span_label(result.span,
format!("can refer to `self::{}`", name));
} else {
- err.span_label(span,
+ err.span_label(result.span,
format!("may refer to `self::{}` in the future", name));
}
}
- for &span in &results.block_scopes {
- err.span_label(span,
+ for result in block_scopes() {
+ err.span_label(result.span,
format!("shadowed by block-scoped `{}`", name));
}
err.help(&format!("write {} explicitly instead", suggestion_choices));