Skip to content

Commit 6e0f2f2

Browse files
committed
Auto merge of rust-lang#32284 - jseyfried:name_conflict_diagnostics, r=eddyb
Resolve: improve diagnostics for duplicate definitions and imports This PR improves and regularizes the diagnostics for duplicate definitions and imports. After this PR, the second of two duplicate definitions/imports will have the following form: > a(n) [value|type|module|trait|extern crate] named \`*name*\` has already been [defined|imported] in this [module|block|trait|enum] with a note referencing this first of the two duplicate definitions/imports: > previous [definition|import] of \`*name*\` here The error indices remain unchanged. r? @eddyb
2 parents eeb062b + b3c6265 commit 6e0f2f2

25 files changed

+134
-174
lines changed

src/librustc_resolve/build_reduced_graph.rs

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -105,36 +105,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
105105
/// otherwise, reports an error.
106106
fn define<T: ToNameBinding<'b>>(&self, parent: Module<'b>, name: Name, ns: Namespace, def: T) {
107107
let binding = def.to_name_binding();
108-
let old_binding = match parent.try_define_child(name, ns, binding.clone()) {
109-
Ok(()) => return,
110-
Err(old_binding) => old_binding,
111-
};
112-
113-
let span = binding.span.unwrap_or(DUMMY_SP);
114-
if !old_binding.is_extern_crate() && !binding.is_extern_crate() {
115-
// Record an error here by looking up the namespace that had the duplicate
116-
let ns_str = match ns { TypeNS => "type or module", ValueNS => "value" };
117-
let resolution_error = ResolutionError::DuplicateDefinition(ns_str, name);
118-
let mut err = resolve_struct_error(self, span, resolution_error);
119-
120-
if let Some(sp) = old_binding.span {
121-
let note = format!("first definition of {} `{}` here", ns_str, name);
122-
err.span_note(sp, &note);
123-
}
124-
err.emit();
125-
} else if old_binding.is_extern_crate() && binding.is_extern_crate() {
126-
span_err!(self.session,
127-
span,
128-
E0259,
129-
"an external crate named `{}` has already been imported into this module",
130-
name);
131-
} else {
132-
span_err!(self.session,
133-
span,
134-
E0260,
135-
"the name `{}` conflicts with an external crate \
136-
that has been imported into this module",
137-
name);
108+
if let Err(old_binding) = parent.try_define_child(name, ns, binding.clone()) {
109+
self.report_conflict(parent, name, ns, old_binding, &binding);
138110
}
139111
}
140112

src/librustc_resolve/lib.rs

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,6 @@ pub enum ResolutionError<'a> {
183183
UndeclaredLabel(&'a str),
184184
/// error E0427: cannot use `ref` binding mode with ...
185185
CannotUseRefBindingModeWith(&'a str),
186-
/// error E0428: duplicate definition
187-
DuplicateDefinition(&'a str, Name),
188186
/// error E0429: `self` imports are only allowed within a { } list
189187
SelfImportsOnlyAllowedWithin,
190188
/// error E0430: `self` import can only appear once in the list
@@ -490,14 +488,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
490488
"cannot use `ref` binding mode with {}",
491489
descr)
492490
}
493-
ResolutionError::DuplicateDefinition(namespace, name) => {
494-
struct_span_err!(resolver.session,
495-
span,
496-
E0428,
497-
"duplicate definition of {} `{}`",
498-
namespace,
499-
name)
500-
}
501491
ResolutionError::SelfImportsOnlyAllowedWithin => {
502492
struct_span_err!(resolver.session,
503493
span,
@@ -3530,8 +3520,62 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
35303520
}
35313521
}
35323522
}
3533-
}
35343523

3524+
fn report_conflict(&self,
3525+
parent: Module,
3526+
name: Name,
3527+
ns: Namespace,
3528+
binding: &NameBinding,
3529+
old_binding: &NameBinding) {
3530+
// Error on the second of two conflicting names
3531+
if old_binding.span.unwrap().lo > binding.span.unwrap().lo {
3532+
return self.report_conflict(parent, name, ns, old_binding, binding);
3533+
}
3534+
3535+
let container = match parent.def {
3536+
Some(Def::Mod(_)) => "module",
3537+
Some(Def::Trait(_)) => "trait",
3538+
None => "block",
3539+
_ => "enum",
3540+
};
3541+
3542+
let (participle, noun) = match old_binding.is_import() || old_binding.is_extern_crate() {
3543+
true => ("imported", "import"),
3544+
false => ("defined", "definition"),
3545+
};
3546+
3547+
let span = binding.span.unwrap();
3548+
let msg = {
3549+
let kind = match (ns, old_binding.module()) {
3550+
(ValueNS, _) => "a value",
3551+
(TypeNS, Some(module)) if module.extern_crate_id.is_some() => "an extern crate",
3552+
(TypeNS, Some(module)) if module.is_normal() => "a module",
3553+
(TypeNS, Some(module)) if module.is_trait() => "a trait",
3554+
(TypeNS, _) => "a type",
3555+
};
3556+
format!("{} named `{}` has already been {} in this {}",
3557+
kind, name, participle, container)
3558+
};
3559+
3560+
let mut err = match (old_binding.is_extern_crate(), binding.is_extern_crate()) {
3561+
(true, true) => struct_span_err!(self.session, span, E0259, "{}", msg),
3562+
(true, _) | (_, true) if binding.is_import() || old_binding.is_import() =>
3563+
struct_span_err!(self.session, span, E0254, "{}", msg),
3564+
(true, _) | (_, true) => struct_span_err!(self.session, span, E0260, "{}", msg),
3565+
_ => match (old_binding.is_import(), binding.is_import()) {
3566+
(false, false) => struct_span_err!(self.session, span, E0428, "{}", msg),
3567+
(true, true) => struct_span_err!(self.session, span, E0252, "{}", msg),
3568+
_ => struct_span_err!(self.session, span, E0255, "{}", msg),
3569+
},
3570+
};
3571+
3572+
let span = old_binding.span.unwrap();
3573+
if span != codemap::DUMMY_SP {
3574+
err.span_note(span, &format!("previous {} of `{}` here", noun, name));
3575+
}
3576+
err.emit();
3577+
}
3578+
}
35353579

35363580
fn names_to_string(names: &[Name]) -> String {
35373581
let mut first = true;

src/librustc_resolve/resolve_imports.rs

Lines changed: 6 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,8 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
513513
let imported_binding = directive.import(binding, privacy_error);
514514
let conflict = module_.try_define_child(target, ns, imported_binding);
515515
if let Err(old_binding) = conflict {
516-
self.report_conflict(target, ns, &directive.import(binding, None), old_binding);
516+
let binding = &directive.import(binding, None);
517+
self.resolver.report_conflict(module_, target, ns, binding, old_binding);
517518
}
518519
}
519520

@@ -650,67 +651,6 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
650651
return Success(());
651652
}
652653

653-
fn report_conflict(&mut self,
654-
name: Name,
655-
ns: Namespace,
656-
binding: &NameBinding,
657-
old_binding: &NameBinding) {
658-
// Error on the second of two conflicting imports
659-
if old_binding.is_import() && binding.is_import() &&
660-
old_binding.span.unwrap().lo > binding.span.unwrap().lo {
661-
self.report_conflict(name, ns, old_binding, binding);
662-
return;
663-
}
664-
665-
if old_binding.is_extern_crate() {
666-
let msg = format!("import `{0}` conflicts with imported crate \
667-
in this module (maybe you meant `use {0}::*`?)",
668-
name);
669-
span_err!(self.resolver.session, binding.span.unwrap(), E0254, "{}", &msg);
670-
} else if old_binding.is_import() {
671-
let ns_word = match (ns, old_binding.module()) {
672-
(ValueNS, _) => "value",
673-
(TypeNS, Some(module)) if module.is_normal() => "module",
674-
(TypeNS, Some(module)) if module.is_trait() => "trait",
675-
(TypeNS, _) => "type",
676-
};
677-
let mut err = struct_span_err!(self.resolver.session,
678-
binding.span.unwrap(),
679-
E0252,
680-
"a {} named `{}` has already been imported \
681-
in this module",
682-
ns_word,
683-
name);
684-
err.span_note(old_binding.span.unwrap(),
685-
&format!("previous import of `{}` here", name));
686-
err.emit();
687-
} else if ns == ValueNS { // Check for item conflicts in the value namespace
688-
let mut err = struct_span_err!(self.resolver.session,
689-
binding.span.unwrap(),
690-
E0255,
691-
"import `{}` conflicts with value in this module",
692-
name);
693-
err.span_note(old_binding.span.unwrap(), "conflicting value here");
694-
err.emit();
695-
} else { // Check for item conflicts in the type namespace
696-
let (what, note) = match old_binding.module() {
697-
Some(ref module) if module.is_normal() =>
698-
("existing submodule", "note conflicting module here"),
699-
Some(ref module) if module.is_trait() =>
700-
("trait in this module", "note conflicting trait here"),
701-
_ => ("type in this module", "note conflicting type here"),
702-
};
703-
let mut err = struct_span_err!(self.resolver.session,
704-
binding.span.unwrap(),
705-
E0256,
706-
"import `{}` conflicts with {}",
707-
name,
708-
what);
709-
err.span_note(old_binding.span.unwrap(), note);
710-
err.emit();
711-
}
712-
}
713-
714654
// Miscellaneous post-processing, including recording reexports, recording shadowed traits,
715655
// reporting conflicts, reporting the PRIVATE_IN_PUBLIC lint, and reporting unresolved imports.
716656
fn finalize_resolutions(&mut self, module: Module<'b>, report_unresolved_imports: bool) {
@@ -720,7 +660,10 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
720660

721661
let mut reexports = Vec::new();
722662
for (&(name, ns), resolution) in module.resolutions.borrow().iter() {
723-
resolution.report_conflicts(|b1, b2| self.report_conflict(name, ns, b1, b2));
663+
resolution.report_conflicts(|b1, b2| {
664+
self.resolver.report_conflict(module, name, ns, b1, b2)
665+
});
666+
724667
let binding = match resolution.binding {
725668
Some(binding) => binding,
726669
None => continue,

src/test/compile-fail/blind-item-block-item-shadow.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ fn main() {
1414
{
1515
struct Bar;
1616
use foo::Bar;
17-
//~^ ERROR import `Bar` conflicts with type in this module
18-
//~^^ ERROR import `Bar` conflicts with value in this module
17+
//~^ ERROR a type named `Bar` has already been defined in this block
18+
//~^^ ERROR a value named `Bar` has already been defined in this block
1919
}
2020
}

src/test/compile-fail/blind-item-item-shadow.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
mod foo { pub mod foo { } }
11+
mod foo { pub mod foo { } } //~ NOTE previous definition of `foo` here
1212

13-
use foo::foo; //~ ERROR import `foo` conflicts with existing submodule
13+
use foo::foo; //~ ERROR a module named `foo` has already been defined in this module
1414

1515
fn main() {}

src/test/compile-fail/enum-and-module-in-same-scope.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
enum Foo {
11+
enum Foo { //~ NOTE previous definition
1212
X
1313
}
1414

15-
mod Foo { //~ ERROR duplicate definition of type or module `Foo`
15+
mod Foo { //~ ERROR a type named `Foo` has already been defined
1616
pub static X: isize = 42;
1717
fn f() { f() } // Check that this does not result in a resolution error
1818
}

src/test/compile-fail/issue-19498.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use self::A; //~ ERROR import `A` conflicts with existing submodule
12-
use self::B; //~ ERROR import `B` conflicts with existing submodule
13-
mod A {}
14-
pub mod B {}
11+
use self::A; //~ NOTE previous import of `A` here
12+
use self::B; //~ NOTE previous import of `B` here
13+
mod A {} //~ ERROR a module named `A` has already been imported in this module
14+
pub mod B {} //~ ERROR a module named `B` has already been imported in this module
1515

1616
mod C {
17-
use C::D; //~ ERROR import `D` conflicts with existing submodule
18-
mod D {}
17+
use C::D; //~ NOTE previous import of `D` here
18+
mod D {} //~ ERROR a module named `D` has already been imported in this module
1919
}
2020

2121
fn main() {}

src/test/compile-fail/issue-21546.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,54 +12,54 @@
1212

1313
#[allow(non_snake_case)]
1414
mod Foo { }
15-
//~^ NOTE first definition of type or module `Foo`
15+
//~^ NOTE previous definition of `Foo` here
1616

1717
#[allow(dead_code)]
1818
struct Foo;
19-
//~^ ERROR duplicate definition of type or module `Foo`
20-
19+
//~^ ERROR a module named `Foo` has already been defined in this module
2120

2221
#[allow(non_snake_case)]
2322
mod Bar { }
24-
//~^ NOTE first definition of type or module `Bar`
23+
//~^ NOTE previous definition of `Bar` here
2524

2625
#[allow(dead_code)]
2726
struct Bar(i32);
28-
//~^ ERROR duplicate definition of type or module `Bar`
27+
//~^ ERROR a module named `Bar` has already been defined
2928

3029

3130
#[allow(dead_code)]
3231
struct Baz(i32);
33-
//~^ NOTE first definition of type or module
32+
//~^ NOTE previous definition
3433

3534
#[allow(non_snake_case)]
3635
mod Baz { }
37-
//~^ ERROR duplicate definition of type or module `Baz`
36+
//~^ ERROR a type named `Baz` has already been defined
3837

3938

4039
#[allow(dead_code)]
4140
struct Qux { x: bool }
42-
//~^ NOTE first definition of type or module
41+
//~^ NOTE previous definition
4342

4443
#[allow(non_snake_case)]
4544
mod Qux { }
46-
//~^ ERROR duplicate definition of type or module `Qux`
45+
//~^ ERROR a type named `Qux` has already been defined
4746

4847

4948
#[allow(dead_code)]
5049
struct Quux;
51-
//~^ NOTE first definition of type or module
50+
//~^ NOTE previous definition
5251

5352
#[allow(non_snake_case)]
5453
mod Quux { }
55-
//~^ ERROR duplicate definition of type or module `Quux`
54+
//~^ ERROR a type named `Quux` has already been defined
5655

5756

5857
#[allow(dead_code)]
5958
enum Corge { A, B }
59+
//~^ NOTE previous definition
6060

6161
#[allow(non_snake_case)]
6262
mod Corge { }
63-
//~^ ERROR duplicate definition of type or module `Corge`
63+
//~^ ERROR a type named `Corge` has already been defined
6464

6565
fn main() { }

src/test/compile-fail/issue-24081.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::ops::Add; //~ ERROR import `Add` conflicts with type in this module
12-
use std::ops::Sub; //~ ERROR import `Sub` conflicts with type in this module
13-
use std::ops::Mul; //~ ERROR import `Mul` conflicts with type in this module
14-
use std::ops::Div; //~ ERROR import `Div` conflicts with existing submodule
15-
use std::ops::Rem; //~ ERROR import `Rem` conflicts with trait in this module
11+
use std::ops::Add; //~ NOTE previous import
12+
use std::ops::Sub; //~ NOTE previous import
13+
use std::ops::Mul; //~ NOTE previous import
14+
use std::ops::Div; //~ NOTE previous import
15+
use std::ops::Rem; //~ NOTE previous import
1616

17-
type Add = bool;
18-
struct Sub { x: f32 }
19-
enum Mul { A, B }
20-
mod Div { }
21-
trait Rem { }
17+
type Add = bool; //~ ERROR a trait named `Add` has already been imported in this module
18+
struct Sub { x: f32 } //~ ERROR a trait named `Sub` has already been imported in this module
19+
enum Mul { A, B } //~ ERROR a trait named `Mul` has already been imported in this module
20+
mod Div { } //~ ERROR a trait named `Div` has already been imported in this module
21+
trait Rem { } //~ ERROR a trait named `Rem` has already been imported in this module
2222

2323
fn main() {}

src/test/compile-fail/issue-28472.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
extern {
1414
fn foo();
1515

16-
pub //~ ERROR duplicate definition
16+
pub //~ ERROR a value named `foo` has already been defined
1717
fn foo();
1818

19-
pub //~ ERROR duplicate definition
19+
pub //~ ERROR a value named `foo` has already been defined
2020
static mut foo: u32;
2121
}
2222

src/test/compile-fail/issue-3099-a.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010

1111
enum a { b, c }
1212

13-
enum a { d, e } //~ ERROR duplicate definition of type or module `a`
13+
enum a { d, e } //~ ERROR a type named `a` has already been defined in this module
1414

1515
fn main() {}

src/test/compile-fail/issue-3099-b.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010

1111
pub mod a {}
1212

13-
pub mod a {} //~ ERROR duplicate definition of type or module `a`
13+
pub mod a {} //~ ERROR a module named `a` has already been defined in this module
1414

1515
fn main() {}

0 commit comments

Comments
 (0)