From bb5807919a4b26ba017d2e2f14f2cc9b3d87a278 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Tue, 16 Sep 2014 17:39:18 -0500 Subject: [PATCH] Cleanup error messages for anonymous impl for types not declared in the current module Followup to RFC 57. Fixes #7607 Fixes #8767 Fixes #12729 Fixes #15060 --- src/librustc/middle/resolve.rs | 81 ++++++++++++++++--- src/test/compile-fail/issue-12729.rs | 23 ++++++ src/test/compile-fail/issue-7607-1.rs | 22 +++++ src/test/compile-fail/issue-7607-2.rs | 26 ++++++ src/test/compile-fail/issue-8767.rs | 18 +++++ .../compile-fail/trait-or-new-type-instead.rs | 5 +- 6 files changed, 163 insertions(+), 12 deletions(-) create mode 100644 src/test/compile-fail/issue-12729.rs create mode 100644 src/test/compile-fail/issue-7607-1.rs create mode 100644 src/test/compile-fail/issue-7607-2.rs create mode 100644 src/test/compile-fail/issue-8767.rs diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 2c18c450eb6..5f0750d2653 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -2945,16 +2945,53 @@ impl<'a> Resolver<'a> { match *name_bindings.type_def.borrow() { None => {} Some(ref ty) => { - let msg = format!("import `{}` conflicts with type in \ - this module", - token::get_name(name).get()); - self.session.span_err(import_span, msg.as_slice()); - match ty.type_span { - None => {} - Some(span) => { - self.session - .span_note(span, - "conflicting type here") + match ty.module_def { + None => { + let msg = format!("import `{}` conflicts with type in \ + this module", + token::get_name(name).get()); + self.session.span_err(import_span, msg.as_slice()); + match ty.type_span { + None => {} + Some(span) => { + self.session + .span_note(span, + "note conflicting type here") + } + } + } + Some(ref module_def) => { + match module_def.kind.get() { + ImplModuleKind => { + match ty.type_span { + None => { /* this can't ever happen */ } + Some(span) => { + let msg = format!("inherent implementations \ + are only allowed on types \ + defined in the current module"); + self.session + .span_err(span, msg.as_slice()); + self.session + .span_note(import_span, + "import from other module here") + } + } + } + _ => { + let msg = format!("import `{}` conflicts with existing \ + submodule", + token::get_name(name).get()); + self.session.span_err(import_span, msg.as_slice()); + match ty.type_span { + None => {} + Some(span) => { + self.session + .span_note(span, + "note conflicting module here") + } + } + } + } } } } @@ -4610,6 +4647,30 @@ impl<'a> Resolver<'a> { }); }); }); + + // Check that the current type is indeed a type, if we have an anonymous impl + if opt_trait_reference.is_none() { + match self_type.node { + // TyPath is the only thing that we handled in `build_reduced_graph_for_item`, + // where we created a module with the name of the type in order to implement + // an anonymous trait. In the case that the path does not resolve to an actual + // type, the result will be that the type name resolves to a module but not + // a type (shadowing any imported modules or types with this name), leading + // to weird user-visible bugs. So we ward this off here. See #15060. + TyPath(ref path, _, path_id) => { + match self.def_map.borrow().find(&path_id) { + // FIXME: should we catch other options and give more precise errors? + Some(&DefMod(_)) => { + self.resolve_error(path.span, "inherent implementations are not \ + allowed for types not defined in \ + the current module."); + } + _ => {} + } + } + _ => { } + } + } } fn check_trait_item(&self, ident: Ident, span: Span) { diff --git a/src/test/compile-fail/issue-12729.rs b/src/test/compile-fail/issue-12729.rs new file mode 100644 index 00000000000..ae033bbf38d --- /dev/null +++ b/src/test/compile-fail/issue-12729.rs @@ -0,0 +1,23 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +pub struct Foo; + +mod bar { + use Foo; + + impl Foo { //~ERROR inherent implementations are only allowed on types defined in the current module + fn baz(&self) {} + } +} +fn main() {} + diff --git a/src/test/compile-fail/issue-7607-1.rs b/src/test/compile-fail/issue-7607-1.rs new file mode 100644 index 00000000000..37878084f03 --- /dev/null +++ b/src/test/compile-fail/issue-7607-1.rs @@ -0,0 +1,22 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +struct Foo { + x: int +} + +impl Fo { //~ERROR inherent implementations are not allowed for types not defined in the current module. + fn foo() {} +} + +fn main() {} + diff --git a/src/test/compile-fail/issue-7607-2.rs b/src/test/compile-fail/issue-7607-2.rs new file mode 100644 index 00000000000..8a7022a9a32 --- /dev/null +++ b/src/test/compile-fail/issue-7607-2.rs @@ -0,0 +1,26 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +pub mod a { + pub struct Foo { a: uint } +} + +pub mod b { + use a::Foo; + impl Foo { //~ERROR inherent implementations are only allowed on types defined in the current module + fn bar(&self) { } + } +} + +pub fn main() { } + + diff --git a/src/test/compile-fail/issue-8767.rs b/src/test/compile-fail/issue-8767.rs new file mode 100644 index 00000000000..c6bb460382c --- /dev/null +++ b/src/test/compile-fail/issue-8767.rs @@ -0,0 +1,18 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +impl B { //~ERROR inherent implementations are not allowed for types not defined in the current module. +} + +fn main() { +} + diff --git a/src/test/compile-fail/trait-or-new-type-instead.rs b/src/test/compile-fail/trait-or-new-type-instead.rs index 1a394aa8c9b..c4b4d197283 100644 --- a/src/test/compile-fail/trait-or-new-type-instead.rs +++ b/src/test/compile-fail/trait-or-new-type-instead.rs @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME(#8767) bad error message; Option is not a module -impl Option { //~ERROR found module name used as a type +// ignore-tidy-linelength + +impl Option { //~ERROR inherent implementations are not allowed for types not defined in the current module. pub fn foo(&self) { } }