Skip to content

Add suggestion for duplicated import. #57973

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 5, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
@@ -238,12 +238,14 @@ impl<'a> Resolver<'a> {
macro_ns: Cell::new(None),
},
type_ns_only,
nested,
};
self.add_import_directive(
module_path,
subclass,
use_tree.span,
id,
item,
root_span,
item.id,
vis,
@@ -260,6 +262,7 @@ impl<'a> Resolver<'a> {
subclass,
use_tree.span,
id,
item,
root_span,
item.id,
vis,
@@ -379,6 +382,9 @@ impl<'a> Resolver<'a> {
source: orig_name,
target: ident,
},
has_attributes: !item.attrs.is_empty(),
use_span_with_attributes: item.span_with_attributes(),
use_span: item.span,
root_span: item.span,
span: item.span,
module_path: Vec::new(),
@@ -824,6 +830,9 @@ impl<'a> Resolver<'a> {
parent_scope: parent_scope.clone(),
imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
subclass: ImportDirectiveSubclass::MacroUse,
use_span_with_attributes: item.span_with_attributes(),
has_attributes: !item.attrs.is_empty(),
use_span: item.span,
root_span: span,
span,
module_path: Vec::new(),
275 changes: 228 additions & 47 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
@@ -63,7 +63,7 @@ use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
use syntax::ptr::P;

use syntax_pos::{Span, DUMMY_SP, MultiSpan};
use syntax_pos::{BytePos, Span, DUMMY_SP, MultiSpan};
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};

use std::cell::{Cell, RefCell};
@@ -1228,6 +1228,16 @@ enum NameBindingKind<'a> {
},
}

impl<'a> NameBindingKind<'a> {
/// Is this a name binding of a import?
fn is_import(&self) -> bool {
match *self {
NameBindingKind::Import { .. } => true,
_ => false,
}
}
}

struct PrivacyError<'a>(Span, Ident, &'a NameBinding<'a>);

struct UseError<'a> {
@@ -5134,64 +5144,235 @@ impl<'a> Resolver<'a> {
);

// See https://github.com/rust-lang/rust/issues/32354
use NameBindingKind::Import;
let directive = match (&new_binding.kind, &old_binding.kind) {
(NameBindingKind::Import { directive, .. }, _) if !new_binding.span.is_dummy() =>
Some((directive, new_binding.span)),
(_, NameBindingKind::Import { directive, .. }) if !old_binding.span.is_dummy() =>
Some((directive, old_binding.span)),
// If there are two imports where one or both have attributes then prefer removing the
// import without attributes.
(Import { directive: new, .. }, Import { directive: old, .. }) if {
!new_binding.span.is_dummy() && !old_binding.span.is_dummy() &&
(new.has_attributes || old.has_attributes)
} => {
if old.has_attributes {
Some((new, new_binding.span, true))
} else {
Some((old, old_binding.span, true))
}
},
// Otherwise prioritize the new binding.
(Import { directive, .. }, other) if !new_binding.span.is_dummy() =>
Some((directive, new_binding.span, other.is_import())),
(other, Import { directive, .. }) if !old_binding.span.is_dummy() =>
Some((directive, old_binding.span, other.is_import())),
_ => None,
};
if let Some((directive, binding_span)) = directive {
let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
format!("Other{}", name)
} else {
format!("other_{}", name)
};

let mut suggestion = None;
match directive.subclass {
ImportDirectiveSubclass::SingleImport { type_ns_only: true, .. } =>
suggestion = Some(format!("self as {}", suggested_name)),
ImportDirectiveSubclass::SingleImport { source, .. } => {
if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0)
.map(|pos| pos as usize) {
if let Ok(snippet) = self.session.source_map()
.span_to_snippet(binding_span) {
if pos <= snippet.len() {
suggestion = Some(format!(
"{} as {}{}",
&snippet[..pos],
suggested_name,
if snippet.ends_with(";") { ";" } else { "" }
))
}
// Check if the target of the use for both bindings is the same.
let duplicate = new_binding.def().opt_def_id() == old_binding.def().opt_def_id();
let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
let from_item = self.extern_prelude.get(&ident)
.map(|entry| entry.introduced_by_item)
.unwrap_or(true);
// Only suggest removing an import if both bindings are to the same def, if both spans
// aren't dummy spans. Further, if both bindings are imports, then the ident must have
// been introduced by a item.
let should_remove_import = duplicate && !has_dummy_span &&
((new_binding.is_extern_crate() || old_binding.is_extern_crate()) || from_item);

match directive {
Some((directive, span, true)) if should_remove_import && directive.is_nested() =>
self.add_suggestion_for_duplicate_nested_use(&mut err, directive, span),
Some((directive, _, true)) if should_remove_import && !directive.is_glob() => {
// Simple case - remove the entire import. Due to the above match arm, this can
// only be a single use so just remove it entirely.
err.span_suggestion(
directive.use_span_with_attributes,
"remove unnecessary import",
String::new(),
Applicability::MaybeIncorrect,
);
},
Some((directive, span, _)) =>
self.add_suggestion_for_rename_of_use(&mut err, name, directive, span),
_ => {},
}

err.emit();
self.name_already_seen.insert(name, span);
}

/// This function adds a suggestion to change the binding name of a new import that conflicts
/// with an existing import.
///
/// ```ignore (diagnostic)
/// help: you can use `as` to change the binding name of the import
/// |
/// LL | use foo::bar as other_bar;
/// | ^^^^^^^^^^^^^^^^^^^^^
/// ```
fn add_suggestion_for_rename_of_use(
&self,
err: &mut DiagnosticBuilder<'_>,
name: Symbol,
directive: &ImportDirective<'_>,
binding_span: Span,
) {
let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
format!("Other{}", name)
} else {
format!("other_{}", name)
};

let mut suggestion = None;
match directive.subclass {
ImportDirectiveSubclass::SingleImport { type_ns_only: true, .. } =>
suggestion = Some(format!("self as {}", suggested_name)),
ImportDirectiveSubclass::SingleImport { source, .. } => {
if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0)
.map(|pos| pos as usize) {
if let Ok(snippet) = self.session.source_map()
.span_to_snippet(binding_span) {
if pos <= snippet.len() {
suggestion = Some(format!(
"{} as {}{}",
&snippet[..pos],
suggested_name,
if snippet.ends_with(";") { ";" } else { "" }
))
}
}
}
ImportDirectiveSubclass::ExternCrate { source, target, .. } =>
suggestion = Some(format!(
"extern crate {} as {};",
source.unwrap_or(target.name),
suggested_name,
)),
_ => unreachable!(),
}
ImportDirectiveSubclass::ExternCrate { source, target, .. } =>
suggestion = Some(format!(
"extern crate {} as {};",
source.unwrap_or(target.name),
suggested_name,
)),
_ => unreachable!(),
}

let rename_msg = "you can use `as` to change the binding name of the import";
if let Some(suggestion) = suggestion {
err.span_suggestion(
binding_span,
rename_msg,
suggestion,
Applicability::MaybeIncorrect,
);
} else {
err.span_label(binding_span, rename_msg);
}
}

let rename_msg = "you can use `as` to change the binding name of the import";
if let Some(suggestion) = suggestion {
err.span_suggestion(
binding_span,
rename_msg,
suggestion,
Applicability::MaybeIncorrect,
);
} else {
err.span_label(binding_span, rename_msg);
/// This function adds a suggestion to remove a unnecessary binding from an import that is
/// nested. In the following example, this function will be invoked to remove the `a` binding
/// in the second use statement:
///
/// ```ignore (diagnostic)
/// use issue_52891::a;
/// use issue_52891::{d, a, e};
/// ```
///
/// The following suggestion will be added:
///
/// ```ignore (diagnostic)
/// use issue_52891::{d, a, e};
/// ^-- help: remove unnecessary import
/// ```
///
/// If the nested use contains only one import then the suggestion will remove the entire
/// line.
///
/// It is expected that the directive provided is a nested import - this isn't checked by the
/// function. If this invariant is not upheld, this function's behaviour will be unexpected
/// as characters expected by span manipulations won't be present.
fn add_suggestion_for_duplicate_nested_use(
&self,
err: &mut DiagnosticBuilder<'_>,
directive: &ImportDirective<'_>,
binding_span: Span,
) {
assert!(directive.is_nested());
let message = "remove unnecessary import";
let source_map = self.session.source_map();

// Two examples will be used to illustrate the span manipulations we're doing:
//
// - Given `use issue_52891::{d, a, e};` where `a` is a duplicate then `binding_span` is
// `a` and `directive.use_span` is `issue_52891::{d, a, e};`.
// - Given `use issue_52891::{d, e, a};` where `a` is a duplicate then `binding_span` is
// `a` and `directive.use_span` is `issue_52891::{d, e, a};`.

// Find the span of everything after the binding.
// ie. `a, e};` or `a};`
let binding_until_end = binding_span.with_hi(directive.use_span.hi());

// Find everything after the binding but not including the binding.
// ie. `, e};` or `};`
let after_binding_until_end = binding_until_end.with_lo(binding_span.hi());

// Keep characters in the span until we encounter something that isn't a comma or
// whitespace.
// ie. `, ` or ``.
//
// Also note whether a closing brace character was encountered. If there
// was, then later go backwards to remove any trailing commas that are left.
let mut found_closing_brace = false;
let after_binding_until_next_binding = source_map.span_take_while(
after_binding_until_end,
|&ch| {
if ch == '}' { found_closing_brace = true; }
ch == ' ' || ch == ','
}
);

// Combine the two spans.
// ie. `a, ` or `a`.
//
// Removing these would leave `issue_52891::{d, e};` or `issue_52891::{d, e, };`
let span = binding_span.with_hi(after_binding_until_next_binding.hi());

// If there was a closing brace then identify the span to remove any trailing commas from
// previous imports.
if found_closing_brace {
if let Ok(prev_source) = source_map.span_to_prev_source(span) {
// `prev_source` will contain all of the source that came before the span.
// Then split based on a command and take the first (ie. closest to our span)
// snippet. In the example, this is a space.
let prev_comma = prev_source.rsplit(',').collect::<Vec<_>>();
let prev_starting_brace = prev_source.rsplit('{').collect::<Vec<_>>();
if prev_comma.len() > 1 && prev_starting_brace.len() > 1 {
let prev_comma = prev_comma.first().unwrap();
let prev_starting_brace = prev_starting_brace.first().unwrap();

// If the amount of source code before the comma is greater than
// the amount of source code before the starting brace then we've only
// got one item in the nested item (eg. `issue_52891::{self}`).
if prev_comma.len() > prev_starting_brace.len() {
// So just remove the entire line...
err.span_suggestion(
directive.use_span_with_attributes,
message,
String::new(),
Applicability::MaybeIncorrect,
);
return;
}

let span = span.with_lo(BytePos(
// Take away the number of bytes for the characters we've found and an
// extra for the comma.
span.lo().0 - (prev_comma.as_bytes().len() as u32) - 1
));
err.span_suggestion(
span, message, String::new(), Applicability::MaybeIncorrect,
);
return;
}
}
}

err.emit();
self.name_already_seen.insert(name, span);
err.span_suggestion(span, message, String::new(), Applicability::MachineApplicable);
}

fn extern_prelude_get(&mut self, ident: Ident, speculative: bool)
28 changes: 25 additions & 3 deletions src/librustc_resolve/resolve_imports.rs
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ use rustc::hir::def::*;
use rustc::session::DiagnosticMessageId;
use rustc::util::nodemap::FxHashSet;

use syntax::ast::{Ident, Name, NodeId, CRATE_NODE_ID};
use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID};
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::hygiene::Mark;
use syntax::symbol::keywords;
@@ -42,6 +42,8 @@ pub enum ImportDirectiveSubclass<'a> {
target_bindings: PerNS<Cell<Option<&'a NameBinding<'a>>>>,
/// `true` for `...::{self [as target]}` imports, `false` otherwise.
type_ns_only: bool,
/// Did this import result from a nested import? ie. `use foo::{bar, baz};`
nested: bool,
},
GlobImport {
is_prelude: bool,
@@ -78,6 +80,15 @@ crate struct ImportDirective<'a> {
/// `UseTree` node.
pub root_id: NodeId,

/// Span of the entire use statement.
pub use_span: Span,

/// Span of the entire use statement with attributes.
pub use_span_with_attributes: Span,

/// Did the use statement have any attributes?
pub has_attributes: bool,

/// Span of this use tree.
pub span: Span,

@@ -98,6 +109,13 @@ impl<'a> ImportDirective<'a> {
match self.subclass { ImportDirectiveSubclass::GlobImport { .. } => true, _ => false }
}

pub fn is_nested(&self) -> bool {
match self.subclass {
ImportDirectiveSubclass::SingleImport { nested, .. } => nested,
_ => false
}
}

crate fn crate_lint(&self) -> CrateLint {
CrateLint::UsePath { root_id: self.root_id, root_span: self.root_span }
}
@@ -390,6 +408,7 @@ impl<'a> Resolver<'a> {
subclass: ImportDirectiveSubclass<'a>,
span: Span,
id: NodeId,
item: &ast::Item,
root_span: Span,
root_id: NodeId,
vis: ty::Visibility,
@@ -402,6 +421,9 @@ impl<'a> Resolver<'a> {
subclass,
span,
id,
use_span: item.span,
use_span_with_attributes: item.span_with_attributes(),
has_attributes: !item.attrs.is_empty(),
root_span,
root_id,
vis: Cell::new(vis),
@@ -787,7 +809,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
let (source, target, source_bindings, target_bindings, type_ns_only) =
match directive.subclass {
SingleImport { source, target, ref source_bindings,
ref target_bindings, type_ns_only } =>
ref target_bindings, type_ns_only, .. } =>
(source, target, source_bindings, target_bindings, type_ns_only),
GlobImport { .. } => {
self.resolve_glob_import(directive);
@@ -908,7 +930,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
let (ident, target, source_bindings, target_bindings, type_ns_only) =
match directive.subclass {
SingleImport { source, target, ref source_bindings,
ref target_bindings, type_ns_only } =>
ref target_bindings, type_ns_only, .. } =>
(source, target, source_bindings, target_bindings, type_ns_only),
GlobImport { is_prelude, ref max_vis } => {
if directive.module_path.len() <= 1 {
7 changes: 7 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
@@ -2164,6 +2164,13 @@ pub struct Item {
pub tokens: Option<TokenStream>,
}

impl Item {
/// Return the span that encompasses the attributes.
pub fn span_with_attributes(&self) -> Span {
self.attrs.iter().fold(self.span, |acc, attr| acc.to(attr.span()))
}
}

/// A function header.
///
/// All the information between the visibility and the name of the function is
9 changes: 4 additions & 5 deletions src/test/ui/double-type-import.stderr
Original file line number Diff line number Diff line change
@@ -4,13 +4,12 @@ error[E0252]: the name `X` is defined multiple times
LL | pub use self::bar::X;
| ------------ previous import of the type `X` here
LL | use self::bar::X;
| ^^^^^^^^^^^^ `X` reimported here
| ----^^^^^^^^^^^^-
| | |
| | `X` reimported here
| help: remove unnecessary import
|
= note: `X` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | use self::bar::X as OtherX;
| ^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

10 changes: 4 additions & 6 deletions src/test/ui/error-codes/E0430.stderr
Original file line number Diff line number Diff line change
@@ -10,15 +10,13 @@ error[E0252]: the name `fmt` is defined multiple times
--> $DIR/E0430.rs:1:22
|
LL | use std::fmt::{self, self}; //~ ERROR E0430
| ---- ^^^^ `fmt` reimported here
| |
| ------^^^^
| | | |
| | | `fmt` reimported here
| | help: remove unnecessary import
| previous import of the module `fmt` here
|
= note: `fmt` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | use std::fmt::{self, self as other_fmt}; //~ ERROR E0430
| ^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

9 changes: 4 additions & 5 deletions src/test/ui/imports/duplicate.stderr
Original file line number Diff line number Diff line change
@@ -4,13 +4,12 @@ error[E0252]: the name `foo` is defined multiple times
LL | use a::foo;
| ------ previous import of the value `foo` here
LL | use a::foo; //~ ERROR the name `foo` is defined multiple times
| ^^^^^^ `foo` reimported here
| ----^^^^^^-
| | |
| | `foo` reimported here
| help: remove unnecessary import
|
= note: `foo` must be defined only once in the value namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | use a::foo as other_foo; //~ ERROR the name `foo` is defined multiple times
| ^^^^^^^^^^^^^^^^^^^

error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
--> $DIR/duplicate.rs:46:15
33 changes: 33 additions & 0 deletions src/test/ui/issues/auxiliary/issue-52891.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
pub mod a {
pub mod inner {
}
}

pub mod b {
pub mod inner {
}
}

pub mod c {}

pub mod d {}

pub mod e {}

pub mod f {}

pub mod g {}

pub mod h {}

pub mod i {}

pub mod j {}

pub mod k {}

pub mod l {}

pub mod m {}

pub mod n {}
18 changes: 8 additions & 10 deletions src/test/ui/issues/issue-26886.stderr
Original file line number Diff line number Diff line change
@@ -4,13 +4,12 @@ error[E0252]: the name `Arc` is defined multiple times
LL | use std::sync::{self, Arc};
| --- previous import of the type `Arc` here
LL | use std::sync::Arc; //~ ERROR the name `Arc` is defined multiple times
| ^^^^^^^^^^^^^^ `Arc` reimported here
| ----^^^^^^^^^^^^^^-
| | |
| | `Arc` reimported here
| help: remove unnecessary import
|
= note: `Arc` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | use std::sync::Arc as OtherArc; //~ ERROR the name `Arc` is defined multiple times
| ^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0252]: the name `sync` is defined multiple times
--> $DIR/issue-26886.rs:4:5
@@ -19,13 +18,12 @@ LL | use std::sync::{self, Arc};
| ---- previous import of the module `sync` here
...
LL | use std::sync; //~ ERROR the name `sync` is defined multiple times
| ^^^^^^^^^ `sync` reimported here
| ----^^^^^^^^^-
| | |
| | `sync` reimported here
| help: remove unnecessary import
|
= note: `sync` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | use std::sync as other_sync; //~ ERROR the name `sync` is defined multiple times
| ^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

10 changes: 4 additions & 6 deletions src/test/ui/issues/issue-45829/import-twice.stderr
Original file line number Diff line number Diff line change
@@ -2,15 +2,13 @@ error[E0252]: the name `A` is defined multiple times
--> $DIR/import-twice.rs:6:14
|
LL | use foo::{A, A};
| - ^ `A` reimported here
| |
| ---^
| || |
| || `A` reimported here
| |help: remove unnecessary import
| previous import of the type `A` here
|
= note: `A` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | use foo::{A, A as OtherA};
| ^^^^^^^^^^^

error: aborting due to previous error

37 changes: 37 additions & 0 deletions src/test/ui/issues/issue-52891.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// aux-build:issue-52891.rs
// run-rustfix

#![allow(warnings)]

extern crate issue_52891;

// Check that we don't suggest renaming duplicate imports but instead
// suggest removing one.

use issue_52891::a;
//~ ERROR `a` is defined multiple times

use issue_52891::{b, c}; //~ ERROR `a` is defined multiple times
use issue_52891::{d, e}; //~ ERROR `a` is defined multiple times
use issue_52891::{f, g}; //~ ERROR `a` is defined multiple times

use issue_52891::{//~ ERROR `a` is defined multiple times
h,
i};
use issue_52891::{j,
//~ ERROR `a` is defined multiple times
k};
use issue_52891::{l,
m}; //~ ERROR `a` is defined multiple times

use issue_52891::a::inner;
use issue_52891::b::inner as other_inner; //~ ERROR `inner` is defined multiple times


//~^ ERROR `issue_52891` is defined multiple times


#[macro_use]
use issue_52891::n; //~ ERROR `n` is defined multiple times

fn main() {}
38 changes: 38 additions & 0 deletions src/test/ui/issues/issue-52891.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// aux-build:issue-52891.rs
// run-rustfix

#![allow(warnings)]

extern crate issue_52891;

// Check that we don't suggest renaming duplicate imports but instead
// suggest removing one.

use issue_52891::a;
use issue_52891::a; //~ ERROR `a` is defined multiple times

use issue_52891::{a, b, c}; //~ ERROR `a` is defined multiple times
use issue_52891::{d, a, e}; //~ ERROR `a` is defined multiple times
use issue_52891::{f, g, a}; //~ ERROR `a` is defined multiple times

use issue_52891::{a, //~ ERROR `a` is defined multiple times
h,
i};
use issue_52891::{j,
a, //~ ERROR `a` is defined multiple times
k};
use issue_52891::{l,
m,
a}; //~ ERROR `a` is defined multiple times

use issue_52891::a::inner;
use issue_52891::b::inner; //~ ERROR `inner` is defined multiple times

use issue_52891::{self};
//~^ ERROR `issue_52891` is defined multiple times

use issue_52891::n;
#[macro_use]
use issue_52891::n; //~ ERROR `n` is defined multiple times

fn main() {}
145 changes: 145 additions & 0 deletions src/test/ui/issues/issue-52891.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
error[E0252]: the name `a` is defined multiple times
--> $DIR/issue-52891.rs:12:5
|
LL | use issue_52891::a;
| -------------- previous import of the module `a` here
LL | use issue_52891::a; //~ ERROR `a` is defined multiple times
| ----^^^^^^^^^^^^^^-
| | |
| | `a` reimported here
| help: remove unnecessary import
|
= note: `a` must be defined only once in the type namespace of this module

error[E0252]: the name `a` is defined multiple times
--> $DIR/issue-52891.rs:14:19
|
LL | use issue_52891::a;
| -------------- previous import of the module `a` here
...
LL | use issue_52891::{a, b, c}; //~ ERROR `a` is defined multiple times
| ^--
| |
| `a` reimported here
| help: remove unnecessary import
|
= note: `a` must be defined only once in the type namespace of this module

error[E0252]: the name `a` is defined multiple times
--> $DIR/issue-52891.rs:15:22
|
LL | use issue_52891::a;
| -------------- previous import of the module `a` here
...
LL | use issue_52891::{d, a, e}; //~ ERROR `a` is defined multiple times
| ^--
| |
| `a` reimported here
| help: remove unnecessary import
|
= note: `a` must be defined only once in the type namespace of this module

error[E0252]: the name `a` is defined multiple times
--> $DIR/issue-52891.rs:16:25
|
LL | use issue_52891::a;
| -------------- previous import of the module `a` here
...
LL | use issue_52891::{f, g, a}; //~ ERROR `a` is defined multiple times
| --^
| | |
| | `a` reimported here
| help: remove unnecessary import
|
= note: `a` must be defined only once in the type namespace of this module

error[E0252]: the name `a` is defined multiple times
--> $DIR/issue-52891.rs:18:19
|
LL | use issue_52891::a;
| -------------- previous import of the module `a` here
...
LL | use issue_52891::{a, //~ ERROR `a` is defined multiple times
| ^--
| |
| `a` reimported here
| help: remove unnecessary import
|
= note: `a` must be defined only once in the type namespace of this module

error[E0252]: the name `a` is defined multiple times
--> $DIR/issue-52891.rs:22:5
|
LL | use issue_52891::a;
| -------------- previous import of the module `a` here
...
LL | a, //~ ERROR `a` is defined multiple times
| ^--
| |
| `a` reimported here
| help: remove unnecessary import
|
= note: `a` must be defined only once in the type namespace of this module

error[E0252]: the name `a` is defined multiple times
--> $DIR/issue-52891.rs:26:5
|
LL | use issue_52891::a;
| -------------- previous import of the module `a` here
...
LL | m,
| ______-
LL | | a}; //~ ERROR `a` is defined multiple times
| | -
| | |
| |_____`a` reimported here
| help: remove unnecessary import
|
= note: `a` must be defined only once in the type namespace of this module

error[E0252]: the name `inner` is defined multiple times
--> $DIR/issue-52891.rs:29:5
|
LL | use issue_52891::a::inner;
| --------------------- previous import of the module `inner` here
LL | use issue_52891::b::inner; //~ ERROR `inner` is defined multiple times
| ^^^^^^^^^^^^^^^^^^^^^ `inner` reimported here
|
= note: `inner` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | use issue_52891::b::inner as other_inner; //~ ERROR `inner` is defined multiple times
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0254]: the name `issue_52891` is defined multiple times
--> $DIR/issue-52891.rs:31:19
|
LL | extern crate issue_52891;
| ------------------------- previous import of the extern crate `issue_52891` here
...
LL | use issue_52891::{self};
| ------------------^^^^--
| | |
| | `issue_52891` reimported here
| help: remove unnecessary import
|
= note: `issue_52891` must be defined only once in the type namespace of this module

error[E0252]: the name `n` is defined multiple times
--> $DIR/issue-52891.rs:36:5
|
LL | use issue_52891::n;
| -------------------
| | |
| | previous import of the module `n` here
| help: remove unnecessary import
LL | #[macro_use]
LL | use issue_52891::n; //~ ERROR `n` is defined multiple times
| ^^^^^^^^^^^^^^ `n` reimported here
|
= note: `n` must be defined only once in the type namespace of this module

error: aborting due to 10 previous errors

Some errors occurred: E0252, E0254.
For more information about an error, try `rustc --explain E0252`.
17 changes: 8 additions & 9 deletions src/test/ui/proc-macro/shadow.stderr
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
error[E0259]: the name `derive_a` is defined multiple times
--> $DIR/shadow.rs:6:1
|
LL | extern crate derive_a;
| ---------------------- previous import of the extern crate `derive_a` here
LL | #[macro_use]
LL | extern crate derive_a; //~ ERROR the name `derive_a` is defined multiple times
| ^^^^^^^^^^^^^^^^^^^^^^ `derive_a` reimported here
LL | extern crate derive_a;
| ---------------------- previous import of the extern crate `derive_a` here
LL | / #[macro_use]
LL | | extern crate derive_a; //~ ERROR the name `derive_a` is defined multiple times
| | ^^^^^^^^^^^^^^^^^^^^^-
| |_|____________________|
| | help: remove unnecessary import
| `derive_a` reimported here
Copy link
Contributor

@estebank estebank Jan 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great behavior, although we probably should make sure we keep the #[macro_use] in the remaining extern statement... (not necessary in this PR)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed this to prefer keeping imports with attributes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It didn't seem to work in this case, but only address if you have time.

|
= note: `derive_a` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | extern crate derive_a as other_derive_a; //~ ERROR the name `derive_a` is defined multiple times
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

9 changes: 4 additions & 5 deletions src/test/ui/resolve/resolve-conflict-import-vs-import.stderr
Original file line number Diff line number Diff line change
@@ -4,13 +4,12 @@ error[E0252]: the name `transmute` is defined multiple times
LL | use std::mem::transmute;
| ------------------- previous import of the value `transmute` here
LL | use std::mem::transmute;
| ^^^^^^^^^^^^^^^^^^^ `transmute` reimported here
| ----^^^^^^^^^^^^^^^^^^^-
| | |
| | `transmute` reimported here
| help: remove unnecessary import
|
= note: `transmute` must be defined only once in the value namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | use std::mem::transmute as other_transmute;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -4,13 +4,12 @@ error[E0254]: the name `core` is defined multiple times
LL | extern crate core;
| ------------------ previous import of the extern crate `core` here
LL | use core;
| ^^^^ `core` reimported here
| ----^^^^-
| | |
| | `core` reimported here
| help: remove unnecessary import
|
= note: `core` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | use core as other_core;
| ^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

9 changes: 4 additions & 5 deletions src/test/ui/use/use-mod.stderr
Original file line number Diff line number Diff line change
@@ -20,13 +20,12 @@ LL | self,
| ---- previous import of the module `bar` here
...
LL | self
| ^^^^ `bar` reimported here
| ^^^^
| |
| `bar` reimported here
| help: remove unnecessary import
|
= note: `bar` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | self as other_bar
|

error: aborting due to 3 previous errors

9 changes: 4 additions & 5 deletions src/test/ui/use/use-paths-as-items.stderr
Original file line number Diff line number Diff line change
@@ -4,13 +4,12 @@ error[E0252]: the name `mem` is defined multiple times
LL | use std::{mem, ptr};
| --- previous import of the module `mem` here
LL | use std::mem; //~ ERROR the name `mem` is defined multiple times
| ^^^^^^^^ `mem` reimported here
| ----^^^^^^^^-
| | |
| | `mem` reimported here
| help: remove unnecessary import
|
= note: `mem` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | use std::mem as other_mem; //~ ERROR the name `mem` is defined multiple times
| ^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error