mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-03 12:13:43 +00:00
rustc_resolve: ignore uniform_paths canaries that resolve to an import of the same crate.
This commit is contained in:
parent
0a33de04cf
commit
d5da94a3b1
@ -199,22 +199,6 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
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 {
|
||||
@ -234,7 +218,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
base.into_iter().collect(),
|
||||
subclass.clone(),
|
||||
source.span,
|
||||
canary_id,
|
||||
id,
|
||||
root_use_tree.span,
|
||||
root_id,
|
||||
ty::Visibility::Invisible,
|
||||
|
@ -620,9 +620,9 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
}
|
||||
|
||||
#[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<
|
||||
@ -661,20 +661,12 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -708,16 +700,36 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
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;
|
||||
}
|
||||
@ -727,26 +739,26 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
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));
|
||||
|
@ -0,0 +1,30 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// run-pass
|
||||
// edition:2018
|
||||
|
||||
use std;
|
||||
use std::io;
|
||||
|
||||
mod foo {
|
||||
pub use std as my_std;
|
||||
}
|
||||
|
||||
mod bar {
|
||||
pub use std::{self};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
io::stdout();
|
||||
self::std::io::stdout();
|
||||
foo::my_std::io::stdout();
|
||||
bar::std::io::stdout();
|
||||
}
|
@ -8,11 +8,13 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// run-pass
|
||||
// edition:2018
|
||||
|
||||
#![feature(uniform_paths)]
|
||||
|
||||
use std;
|
||||
use std::io;
|
||||
|
||||
mod foo {
|
||||
pub use std as my_std;
|
||||
@ -23,6 +25,7 @@ mod bar {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
io::stdout();
|
||||
self::std::io::stdout();
|
||||
foo::my_std::io::stdout();
|
||||
bar::std::io::stdout();
|
Loading…
Reference in New Issue
Block a user