Auto merge of #54005 - eddyb:uniform-paths-self-resolve, r=petrochenkov
rustc_resolve: allow `use crate_name;` under `uniform_paths`. Specifically, `use crate_name;` and `use crate_name::{self, ...};` are now allowed, whereas previously there would produce a (false positive) ambiguity error, as the ambiguity detection code was seeing the `crate_name` import as a locally-available definition to conflict with the crate. r? @petrochenkov cc @aturon @joshtriplett @Centril
This commit is contained in:
commit
ad7b22ef29
4 changed files with 39 additions and 32 deletions
|
@ -181,6 +181,23 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||||
self.session.features_untracked().uniform_paths);
|
self.session.features_untracked().uniform_paths);
|
||||||
|
|
||||||
let source = module_path[0];
|
let source = module_path[0];
|
||||||
|
|
||||||
|
// 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.
|
// Helper closure to emit a canary with the given base path.
|
||||||
let emit = |this: &mut Self, base: Option<Ident>| {
|
let emit = |this: &mut Self, base: Option<Ident>| {
|
||||||
let subclass = SingleImport {
|
let subclass = SingleImport {
|
||||||
|
@ -200,7 +217,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||||
base.into_iter().collect(),
|
base.into_iter().collect(),
|
||||||
subclass.clone(),
|
subclass.clone(),
|
||||||
source.span,
|
source.span,
|
||||||
id,
|
canary_id,
|
||||||
root_use_tree.span,
|
root_use_tree.span,
|
||||||
root_id,
|
root_id,
|
||||||
ty::Visibility::Invisible,
|
ty::Visibility::Invisible,
|
||||||
|
|
|
@ -664,6 +664,14 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||||
|
|
||||||
self.per_ns(|_, ns| {
|
self.per_ns(|_, ns| {
|
||||||
if let Some(result) = result[ns].get().ok() {
|
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 {
|
if has_explicit_self {
|
||||||
// There should only be one `self::x` (module-scoped) canary.
|
// There should only be one `self::x` (module-scoped) canary.
|
||||||
assert_eq!(canary_results[ns].module_scope, None);
|
assert_eq!(canary_results[ns].module_scope, None);
|
||||||
|
@ -718,22 +726,6 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||||
|
|
||||||
errors = true;
|
errors = true;
|
||||||
|
|
||||||
// Special-case the error when `self::x` finds its own `use x;`.
|
|
||||||
if has_external_crate &&
|
|
||||||
results.module_scope == Some(span) &&
|
|
||||||
results.block_scopes.is_empty() {
|
|
||||||
let msg = format!("`{}` import is redundant", name);
|
|
||||||
this.session.struct_span_err(span, &msg)
|
|
||||||
.span_label(span,
|
|
||||||
format!("refers to external crate `::{}`", name))
|
|
||||||
.span_label(span,
|
|
||||||
format!("defines `self::{}`, shadowing itself", name))
|
|
||||||
.help(&format!("remove or write `::{}` explicitly instead", name))
|
|
||||||
.note("relative `use` paths enabled by `#![feature(uniform_paths)]`")
|
|
||||||
.emit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let msg = format!("`{}` import is ambiguous", name);
|
let msg = format!("`{}` import is ambiguous", name);
|
||||||
let mut err = this.session.struct_span_err(span, &msg);
|
let mut err = this.session.struct_span_err(span, &msg);
|
||||||
let mut suggestion_choices = String::new();
|
let mut suggestion_choices = String::new();
|
||||||
|
|
|
@ -14,4 +14,16 @@
|
||||||
|
|
||||||
use std;
|
use std;
|
||||||
|
|
||||||
fn main() {}
|
mod foo {
|
||||||
|
pub use std as my_std;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod bar {
|
||||||
|
pub use std::{self};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
self::std::io::stdout();
|
||||||
|
foo::my_std::io::stdout();
|
||||||
|
bar::std::io::stdout();
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
error: `std` import is redundant
|
|
||||||
--> $DIR/redundant.rs:15:5
|
|
||||||
|
|
|
||||||
LL | use std;
|
|
||||||
| ^^^
|
|
||||||
| |
|
|
||||||
| refers to external crate `::std`
|
|
||||||
| defines `self::std`, shadowing itself
|
|
||||||
|
|
|
||||||
= help: remove or write `::std` explicitly instead
|
|
||||||
= note: relative `use` paths enabled by `#![feature(uniform_paths)]`
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue