about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAndrew Poelstra <apoelstra@wpsoftware.net>2014-09-16 17:39:18 -0500
committerAndrew Poelstra <apoelstra@wpsoftware.net>2014-09-28 12:58:10 -0500
commitbb5807919a4b26ba017d2e2f14f2cc9b3d87a278 (patch)
treef04fb08c60f7a0a810ad8d18c61c50c6d08001ca
parent9a68da7401d9bef645a8b6a4e0ce4cae12604df4 (diff)
downloadrust-bb5807919a4b26ba017d2e2f14f2cc9b3d87a278.tar.gz
rust-bb5807919a4b26ba017d2e2f14f2cc9b3d87a278.zip
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
-rw-r--r--src/librustc/middle/resolve.rs81
-rw-r--r--src/test/compile-fail/issue-12729.rs23
-rw-r--r--src/test/compile-fail/issue-7607-1.rs22
-rw-r--r--src/test/compile-fail/issue-7607-2.rs26
-rw-r--r--src/test/compile-fail/issue-8767.rs18
-rw-r--r--src/test/compile-fail/trait-or-new-type-instead.rs5
6 files changed, 163 insertions, 12 deletions
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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T> Option<T> { //~ERROR found module name used as a type
+// ignore-tidy-linelength
+
+impl<T> Option<T> { //~ERROR inherent implementations are not allowed for types not defined in the current module.
     pub fn foo(&self) { }
 }