Skip to content

Clearer Error Message for Duplicate Definition #42076

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
Jun 21, 2017
Merged
Show file tree
Hide file tree
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
62 changes: 39 additions & 23 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3454,11 +3454,11 @@ impl<'a> Resolver<'a> {
parent: Module,
ident: Ident,
ns: Namespace,
binding: &NameBinding,
new_binding: &NameBinding,
old_binding: &NameBinding) {
// Error on the second of two conflicting names
if old_binding.span.lo > binding.span.lo {
return self.report_conflict(parent, ident, ns, old_binding, binding);
if old_binding.span.lo > new_binding.span.lo {
return self.report_conflict(parent, ident, ns, old_binding, new_binding);
}

let container = match parent.kind {
Expand All @@ -3468,49 +3468,65 @@ impl<'a> Resolver<'a> {
_ => "enum",
};

let (participle, noun) = match old_binding.is_import() {
true => ("imported", "import"),
false => ("defined", "definition"),
let old_noun = match old_binding.is_import() {
true => "import",
false => "definition",
};

let (name, span) = (ident.name, binding.span);
let new_participle = match new_binding.is_import() {
true => "imported",
false => "defined",
};

let (name, span) = (ident.name, new_binding.span);

if let Some(s) = self.name_already_seen.get(&name) {
if s == &span {
return;
}
}

let msg = {
let kind = match (ns, old_binding.module()) {
(ValueNS, _) => "a value",
(MacroNS, _) => "a macro",
(TypeNS, _) if old_binding.is_extern_crate() => "an extern crate",
(TypeNS, Some(module)) if module.is_normal() => "a module",
(TypeNS, Some(module)) if module.is_trait() => "a trait",
(TypeNS, _) => "a type",
};
format!("{} named `{}` has already been {} in this {}",
kind, name, participle, container)
let old_kind = match (ns, old_binding.module()) {
(ValueNS, _) => "value",
(MacroNS, _) => "macro",
(TypeNS, _) if old_binding.is_extern_crate() => "extern crate",
(TypeNS, Some(module)) if module.is_normal() => "module",
(TypeNS, Some(module)) if module.is_trait() => "trait",
(TypeNS, _) => "type",
};

let namespace = match ns {
ValueNS => "value",
MacroNS => "macro",
TypeNS => "type",
};

let mut err = match (old_binding.is_extern_crate(), binding.is_extern_crate()) {
let msg = format!("the name `{}` is defined multiple times", name);

let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
(true, true) => struct_span_err!(self.session, span, E0259, "{}", msg),
(true, _) | (_, true) => match binding.is_import() && old_binding.is_import() {
(true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() {
true => struct_span_err!(self.session, span, E0254, "{}", msg),
false => struct_span_err!(self.session, span, E0260, "{}", msg),
},
_ => match (old_binding.is_import(), binding.is_import()) {
_ => match (old_binding.is_import(), new_binding.is_import()) {
(false, false) => struct_span_err!(self.session, span, E0428, "{}", msg),
(true, true) => struct_span_err!(self.session, span, E0252, "{}", msg),
_ => struct_span_err!(self.session, span, E0255, "{}", msg),
},
};

err.span_label(span, format!("`{}` already {}", name, participle));
err.note(&format!("`{}` must be defined only once in the {} namespace of this {}",
name,
namespace,
container));

err.span_label(span, format!("`{}` re{} here", name, new_participle));
if old_binding.span != syntax_pos::DUMMY_SP {
err.span_label(old_binding.span, format!("previous {} of `{}` here", noun, name));
err.span_label(old_binding.span, format!("previous {} of the {} `{}` here",
old_noun, old_kind, name));
}

err.emit();
self.name_already_seen.insert(name, span);
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail-fulldeps/proc-macro/shadow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
#[macro_use]
extern crate derive_a;
#[macro_use]
extern crate derive_a; //~ ERROR `derive_a` has already been imported
extern crate derive_a; //~ ERROR the name `derive_a` is defined multiple times

fn main() {}
5 changes: 3 additions & 2 deletions src/test/compile-fail/E0254.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#![feature(alloc)]

extern crate alloc;
//~^ NOTE previous import of `alloc` here
//~^ NOTE previous import of the extern crate `alloc` here

mod foo {
pub trait alloc {
Expand All @@ -21,6 +21,7 @@ mod foo {

use foo::alloc;
//~^ ERROR E0254
//~| NOTE already imported
//~| NOTE `alloc` reimported here
//~| NOTE `alloc` must be defined only once in the type namespace of this module

fn main() {}
5 changes: 3 additions & 2 deletions src/test/compile-fail/E0259.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
#![feature(alloc, libc)]

extern crate alloc;
//~^ NOTE previous import of `alloc` here
//~^ NOTE previous import of the extern crate `alloc` here

extern crate libc as alloc;
//~^ ERROR E0259
//~| NOTE `alloc` already imported
//~| NOTE `alloc` reimported here
//~| NOTE `alloc` must be defined only once in the type namespace of this module

fn main() {}
7 changes: 4 additions & 3 deletions src/test/compile-fail/E0260.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
#![feature(alloc)]

extern crate alloc;
//~^ NOTE previous import of `alloc` here
//~^ NOTE previous import of the extern crate `alloc` here

mod alloc {
//~^ ERROR `alloc` has already been imported in this module [E0260]
//~| NOTE `alloc` already imported
//~^ ERROR the name `alloc` is defined multiple times [E0260]
//~| NOTE `alloc` redefined here
//~| NOTE `alloc` must be defined only once in the type namespace of this module
pub trait MyTrait {
fn do_something();
}
Expand Down
5 changes: 3 additions & 2 deletions src/test/compile-fail/E0428.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

struct Bar; //~ previous definition of `Bar` here
struct Bar; //~ previous definition of the type `Bar` here
struct Bar; //~ ERROR E0428
//~| NOTE already defined
//~| NOTE `Bar` redefined here
//~| NOTE `Bar` must be defined only once in the type namespace of this module

fn main () {
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/blind-item-block-item-shadow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ fn main() {
{
struct Bar;
use foo::Bar;
//~^ ERROR a type named `Bar` has already been defined in this block
//~^ ERROR the name `Bar` is defined multiple times
}
}
7 changes: 4 additions & 3 deletions src/test/compile-fail/blind-item-item-shadow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

mod foo { pub mod foo { } } //~ NOTE previous definition of `foo` here
mod foo { pub mod foo { } } //~ NOTE previous definition of the module `foo` here

use foo::foo;
//~^ ERROR a module named `foo` has already been defined in this module
//~| `foo` already defined
//~^ ERROR the name `foo` is defined multiple times
//~| `foo` reimported here
//~| NOTE `foo` must be defined only once in the type namespace of this module

fn main() {}
7 changes: 4 additions & 3 deletions src/test/compile-fail/double-import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ mod sub2 {
pub fn foo() {} // implementation 2
}

use sub1::foo; //~ NOTE previous import of `foo` here
use sub2::foo; //~ ERROR a value named `foo` has already been imported in this module [E0252]
//~| NOTE already imported
use sub1::foo; //~ NOTE previous import of the value `foo` here
use sub2::foo; //~ ERROR the name `foo` is defined multiple times
//~| NOTE `foo` reimported here
//~| NOTE `foo` must be defined only once in the value namespace of this module

fn main() {}
2 changes: 1 addition & 1 deletion src/test/compile-fail/double-type-import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
mod foo {
pub use self::bar::X;
use self::bar::X;
//~^ ERROR a type named `X` has already been imported in this module
//~^ ERROR the name `X` is defined multiple times

mod bar {
pub struct X;
Expand Down
7 changes: 4 additions & 3 deletions src/test/compile-fail/enum-and-module-in-same-scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

enum Foo { //~ NOTE previous definition of `Foo` here
enum Foo { //~ NOTE previous definition of the type `Foo` here
X
}

mod Foo { //~ ERROR a type named `Foo` has already been defined
//~| NOTE already defined
mod Foo { //~ ERROR the name `Foo` is defined multiple times
//~| NOTE `Foo` redefined here
//~| NOTE `Foo` must be defined only once in the type namespace of this module
pub static X: isize = 42;
fn f() { f() } // Check that this does not result in a resolution error
}
Expand Down
7 changes: 4 additions & 3 deletions src/test/compile-fail/imports/duplicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ mod c {
}

mod d {
use a::foo; //~ NOTE previous import
use a::foo; //~ ERROR `foo` has already been imported
//~| NOTE already imported
use a::foo; //~ NOTE previous import of the value `foo` here
use a::foo; //~ ERROR the name `foo` is defined multiple times
//~| NOTE `foo` reimported here
//~| NOTE `foo` must be defined only once in the value namespace of this module
}

mod e {
Expand Down
21 changes: 12 additions & 9 deletions src/test/compile-fail/issue-19498.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use self::A; //~ NOTE previous import of `A` here
use self::B; //~ NOTE previous import of `B` here
mod A {} //~ ERROR a module named `A` has already been imported in this module
//~| `A` already imported
pub mod B {} //~ ERROR a module named `B` has already been imported in this module
//~| `B` already imported
use self::A; //~ NOTE previous import of the module `A` here
use self::B; //~ NOTE previous import of the module `B` here
mod A {} //~ ERROR the name `A` is defined multiple times
//~| `A` redefined here
//~| NOTE `A` must be defined only once in the type namespace of this module
pub mod B {} //~ ERROR the name `B` is defined multiple times
//~| `B` redefined here
//~| NOTE `B` must be defined only once in the type namespace of this module
mod C {
use C::D; //~ NOTE previous import of `D` here
mod D {} //~ ERROR a module named `D` has already been imported in this module
//~| `D` already imported
use C::D; //~ NOTE previous import of the module `D` here
mod D {} //~ ERROR the name `D` is defined multiple times
//~| `D` redefined here
//~| NOTE `D` must be defined only once in the type namespace of this module
}

fn main() {}
42 changes: 24 additions & 18 deletions src/test/compile-fail/issue-21546.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,60 +12,66 @@

#[allow(non_snake_case)]
mod Foo { }
//~^ NOTE previous definition of `Foo` here
//~^ NOTE previous definition of the module `Foo` here

#[allow(dead_code)]
struct Foo;
//~^ ERROR a module named `Foo` has already been defined in this module
//~| NOTE already defined
//~^ ERROR the name `Foo` is defined multiple times
//~| NOTE `Foo` redefined here
//~| NOTE `Foo` must be defined only once in the type namespace of this module

#[allow(non_snake_case)]
mod Bar { }
//~^ NOTE previous definition of `Bar` here
//~^ NOTE previous definition of the module `Bar` here

#[allow(dead_code)]
struct Bar(i32);
//~^ ERROR a module named `Bar` has already been defined
//~| NOTE already defined
//~^ ERROR the name `Bar` is defined multiple times
//~| NOTE `Bar` redefined here
//~| NOTE `Bar` must be defined only once in the type namespace of this module


#[allow(dead_code)]
struct Baz(i32);
//~^ NOTE previous definition
//~^ NOTE previous definition of the type `Baz` here

#[allow(non_snake_case)]
mod Baz { }
//~^ ERROR a type named `Baz` has already been defined
//~| NOTE already defined
//~^ ERROR the name `Baz` is defined multiple times
//~| NOTE `Baz` redefined here
//~| NOTE `Baz` must be defined only once in the type namespace of this module


#[allow(dead_code)]
struct Qux { x: bool }
//~^ NOTE previous definition
//~^ NOTE previous definition of the type `Qux` here

#[allow(non_snake_case)]
mod Qux { }
//~^ ERROR a type named `Qux` has already been defined
//~| NOTE already defined
//~^ ERROR the name `Qux` is defined multiple times
//~| NOTE `Qux` redefined here
//~| NOTE `Qux` must be defined only once in the type namespace of this module


#[allow(dead_code)]
struct Quux;
//~^ NOTE previous definition
//~^ NOTE previous definition of the type `Quux` here

#[allow(non_snake_case)]
mod Quux { }
//~^ ERROR a type named `Quux` has already been defined
//~| NOTE already defined
//~^ ERROR the name `Quux` is defined multiple times
//~| NOTE `Quux` redefined here
//~| NOTE `Quux` must be defined only once in the type namespace of this module


#[allow(dead_code)]
enum Corge { A, B }
//~^ NOTE previous definition
//~^ NOTE previous definition of the type `Corge` here

#[allow(non_snake_case)]
mod Corge { }
//~^ ERROR a type named `Corge` has already been defined
//~| NOTE already defined
//~^ ERROR the name `Corge` is defined multiple times
//~| NOTE `Corge` redefined here
//~| NOTE `Corge` must be defined only once in the type namespace of this module

fn main() { }
Loading