]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #32131 - petrochenkov:prim, r=eddyb
authorManish Goregaokar <manishsmail@gmail.com>
Sat, 26 Mar 2016 03:37:20 +0000 (09:07 +0530)
committerManish Goregaokar <manishsmail@gmail.com>
Sat, 26 Mar 2016 03:37:20 +0000 (09:07 +0530)
resolve: Minimize hacks in name resolution of primitive types

When resolving the first unqualified segment in a path with `n` segments and `n - 1` associated item segments, e.g. (`a` or `a::assoc` or `a::assoc::assoc` etc) try to resolve `a` without considering primitive types first. If the "normal" lookup fails or results in a module, then try to resolve `a` as a primitive type as a fallback.

This way backward compatibility is respected, but the restriction from E0317 can be lifted, i.e. primitive names mostly can be shadowed like any other names.

Furthermore, if names of primitive types are [put into prelude](https://github.com/petrochenkov/rust/tree/prim2) (now it's possible to do), then most of names will be resolved in conventional way and amount of code relying on this fallback will be greatly reduced. Although, it's not entirely convenient to put them into prelude right now due to temporary conflicts like `use prelude::v1::*; use usize;` in libcore/libstd, I'd better wait for proper glob shadowing before doing it.
I wish the `no_prelude` attribute were unstable as intended :(

cc @jseyfried @arielb1
r? @eddyb

src/librustc_resolve/diagnostics.rs
src/librustc_resolve/lib.rs
src/test/compile-fail/issue-20427.rs [deleted file]
src/test/run-pass/issue-20427.rs [new file with mode: 0644]

index bfd8a6f1f61f0b385369e08967ed4ab1a375326c..8a196768ae5168ea178c4c7f1f511b787474c0c7 100644 (file)
@@ -205,51 +205,6 @@ fn main() {}
 https://doc.rust-lang.org/reference.html#statements
 "##,
 
-E0317: r##"
-User-defined types or type parameters cannot shadow the primitive types.
-This error indicates you tried to define a type, struct or enum with the same
-name as an existing primitive type:
-
-```compile_fail
-struct u8 {
-    // ...
-}
-```
-
-To fix this, simply name it something else.
-
-Such an error may also occur if you define a type parameter which shadows a
-primitive type. An example would be something like:
-
-```compile_fail
-impl<u8> MyTrait for Option<u8> {
-    // ...
-}
-```
-
-In such a case, if you meant for `u8` to be a generic type parameter (i.e. any
-type can be used in its place), use something like `T` instead:
-
-```ignore
-impl<T> MyTrait for Option<T> {
-    // ...
-}
-```
-
-On the other hand, if you wished to refer to the specific type `u8`, remove it
-from the type parameter list:
-
-```ignore
-impl MyTrait for Option<u8> {
-    // ...
-}
-
-See the Types section of the reference for more information about the primitive
-types:
-
-https://doc.rust-lang.org/reference.html#types
-"##,
-
 E0364: r##"
 Private items cannot be publicly re-exported.  This error indicates that you
 attempted to `pub use` a type or value that was not itself public.
index 77fdc657b886fa7ec55d8e4086284a01ef1a7bcc..ab1d708f952ef02f57c6956746805575391abe81 100644 (file)
@@ -1619,15 +1619,6 @@ fn resolve_crate(&mut self, krate: &hir::Crate) {
         intravisit::walk_crate(self, krate);
     }
 
-    fn check_if_primitive_type_name(&self, name: Name, span: Span) {
-        if let Some(_) = self.primitive_type_table.primitive_types.get(&name) {
-            span_err!(self.session,
-                      span,
-                      E0317,
-                      "user-defined types or type parameters cannot shadow the primitive types");
-        }
-    }
-
     fn resolve_item(&mut self, item: &Item) {
         let name = item.name;
 
@@ -1637,8 +1628,6 @@ fn resolve_item(&mut self, item: &Item) {
             ItemEnum(_, ref generics) |
             ItemTy(_, ref generics) |
             ItemStruct(_, ref generics) => {
-                self.check_if_primitive_type_name(name, item.span);
-
                 self.with_type_parameter_rib(HasTypeParameters(generics, TypeSpace, ItemRibKind),
                                              |this| intravisit::walk_item(this, item));
             }
@@ -1659,8 +1648,6 @@ fn resolve_item(&mut self, item: &Item) {
             }
 
             ItemTrait(_, ref generics, ref bounds, ref trait_items) => {
-                self.check_if_primitive_type_name(name, item.span);
-
                 // Create a new rib for the trait-wide type parameters.
                 self.with_type_parameter_rib(HasTypeParameters(generics,
                                                                TypeSpace,
@@ -1695,8 +1682,6 @@ fn resolve_item(&mut self, item: &Item) {
                                     });
                                 }
                                 hir::TypeTraitItem(..) => {
-                                    this.check_if_primitive_type_name(trait_item.name,
-                                                                      trait_item.span);
                                     this.with_type_parameter_rib(NoTypeParameters, |this| {
                                         intravisit::walk_trait_item(this, trait_item)
                                     });
@@ -1720,28 +1705,8 @@ fn resolve_item(&mut self, item: &Item) {
             }
 
             ItemUse(ref view_path) => {
-                // check for imports shadowing primitive types
-                let check_rename = |this: &Self, id, name| {
-                    match this.def_map.borrow().get(&id).map(|d| d.full_def()) {
-                        Some(Def::Enum(..)) | Some(Def::TyAlias(..)) | Some(Def::Struct(..)) |
-                        Some(Def::Trait(..)) | None => {
-                            this.check_if_primitive_type_name(name, item.span);
-                        }
-                        _ => {}
-                    }
-                };
-
                 match view_path.node {
-                    hir::ViewPathSimple(name, _) => {
-                        check_rename(self, item.id, name);
-                    }
                     hir::ViewPathList(ref prefix, ref items) => {
-                        for item in items {
-                            if let Some(name) = item.node.rename() {
-                                check_rename(self, item.node.id(), name);
-                            }
-                        }
-
                         // Resolve prefix of an import with empty braces (issue #28388)
                         if items.is_empty() && !prefix.segments.is_empty() {
                             match self.resolve_crate_relative_path(prefix.span,
@@ -1922,9 +1887,6 @@ fn resolve_trait_reference(&mut self,
     }
 
     fn resolve_generics(&mut self, generics: &Generics) {
-        for type_parameter in generics.ty_params.iter() {
-            self.check_if_primitive_type_name(type_parameter.name, type_parameter.span);
-        }
         for predicate in &generics.where_clause.predicates {
             match predicate {
                 &hir::WherePredicate::BoundPredicate(_) |
@@ -2658,15 +2620,37 @@ pub fn resolve_path(&mut self,
 
         // Try to find a path to an item in a module.
         let last_ident = segments.last().unwrap().identifier;
-        if segments.len() <= 1 {
-            let unqualified_def = self.resolve_identifier(last_ident, namespace, true);
-            return unqualified_def.and_then(|def| self.adjust_local_def(def, span))
-                                  .map(|def| {
-                                      PathResolution::new(def, path_depth)
-                                  });
-        }
+        // Resolve a single identifier with fallback to primitive types
+        let resolve_identifier_with_fallback = |this: &mut Self, record_used| {
+            let def = this.resolve_identifier(last_ident, namespace, record_used);
+            match def {
+                None | Some(LocalDef{def: Def::Mod(..), ..}) if namespace == TypeNS =>
+                    this.primitive_type_table
+                        .primitive_types
+                        .get(&last_ident.unhygienic_name)
+                        .map_or(def, |prim_ty| Some(LocalDef::from_def(Def::PrimTy(*prim_ty)))),
+                _ => def
+            }
+        };
 
-        let unqualified_def = self.resolve_identifier(last_ident, namespace, false);
+        if segments.len() == 1 {
+            // In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we
+            // don't report an error right away, but try to fallback to a primitive type.
+            // So, we are still able to successfully resolve something like
+            //
+            // use std::u8; // bring module u8 in scope
+            // fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
+            //     u8::max_value() // OK, resolves to associated function <u8>::max_value,
+            //                     // not to non-existent std::u8::max_value
+            // }
+            //
+            // Such behavior is required for backward compatibility.
+            // The same fallback is used when `a` resolves to nothing.
+            let unqualified_def = resolve_identifier_with_fallback(self, true);
+            return unqualified_def.and_then(|def| self.adjust_local_def(def, span)).map(mk_res);
+        }
+
+        let unqualified_def = resolve_identifier_with_fallback(self, false);
         let def = self.resolve_module_relative_path(span, segments, namespace);
         match (def, unqualified_def) {
             (Some(d), Some(ref ud)) if d == ud.def => {
@@ -2692,15 +2676,6 @@ fn resolve_identifier(&mut self,
             return Some(LocalDef::from_def(Def::Err));
         }
 
-        // First, check to see whether the name is a primitive type.
-        if namespace == TypeNS {
-            if let Some(&prim_ty) = self.primitive_type_table
-                                        .primitive_types
-                                        .get(&identifier.unhygienic_name) {
-                return Some(LocalDef::from_def(Def::PrimTy(prim_ty)));
-            }
-        }
-
         self.resolve_identifier_in_local_ribs(identifier, namespace, record_used)
     }
 
diff --git a/src/test/compile-fail/issue-20427.rs b/src/test/compile-fail/issue-20427.rs
deleted file mode 100644 (file)
index 99dd22a..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2015 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.
-
-// aux-build:i8.rs
-extern crate i8;
-use std::string as i16;
-static i32: i32 = 0;
-const i64: i64 = 0;
-fn u8(f32: f32) {}
-fn f<f64>(f64: f64) {}
-//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
-type u16 = u16; //~ ERROR user-defined types or type parameters cannot shadow the primitive types
-enum u32 {} //~ ERROR user-defined types or type parameters cannot shadow the primitive types
-struct u64; //~ ERROR user-defined types or type parameters cannot shadow the primitive types
-trait bool {} //~ ERROR user-defined types or type parameters cannot shadow the primitive types
-
-mod char {
-    extern crate i8;
-    static i32_: i32 = 0;
-    const i64_: i64 = 0;
-    fn u8_(f32: f32) {}
-    fn f_<f64_>(f64: f64_) {}
-    type u16_ = u16;
-    enum u32_ {}
-    struct u64_;
-    trait bool_ {}
-    mod char_ {}
-
-    mod str {
-        use super::i8 as i8;
-        use super::i32_ as i32;
-        use super::i64_ as i64;
-        use super::u8_ as u8;
-        use super::f_ as f64;
-        use super::u16_ as u16;
-        //~^ ERROR user-defined types or type parameters cannot shadow the primitive types
-        use super::u32_ as u32;
-        //~^ ERROR user-defined types or type parameters cannot shadow the primitive types
-        use super::u64_ as u64;
-        //~^ ERROR user-defined types or type parameters cannot shadow the primitive types
-        use super::bool_ as bool;
-        //~^ ERROR user-defined types or type parameters cannot shadow the primitive types
-        use super::{bool_ as str};
-        //~^ ERROR user-defined types or type parameters cannot shadow the primitive types
-        use super::char_ as char;
-    }
-}
-
-trait isize_ {
-    type isize; //~ ERROR user-defined types or type parameters cannot shadow the primitive types
-}
-
-fn usize<'usize>(usize: &'usize usize) -> &'usize usize { usize }
-
-fn main() {
-    let bool = true;
-    match bool {
-        str @ true => if str { i32 as i64 } else { i64 },
-        false => i64,
-    };
-}
diff --git a/src/test/run-pass/issue-20427.rs b/src/test/run-pass/issue-20427.rs
new file mode 100644 (file)
index 0000000..dd3d952
--- /dev/null
@@ -0,0 +1,91 @@
+// Copyright 2016 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.
+
+// aux-build:i8.rs
+// ignore-pretty (#23623)
+
+extern crate i8;
+use std::string as i16;
+static i32: i32 = 0;
+const i64: i64 = 0;
+fn u8(f32: f32) {}
+fn f<f64>(f64: f64) {}
+enum u32 {}
+struct u64;
+trait bool {}
+
+mod char {
+    extern crate i8;
+    static i32_: i32 = 0;
+    const i64_: i64 = 0;
+    fn u8_(f32: f32) {}
+    fn f_<f64_>(f64: f64_) {}
+    type u16_ = u16;
+    enum u32_ {}
+    struct u64_;
+    trait bool_ {}
+    mod char_ {}
+
+    mod str {
+        use super::i8 as i8;
+        use super::i32_ as i32;
+        use super::i64_ as i64;
+        use super::u8_ as u8;
+        use super::f_ as f64;
+        use super::u16_ as u16;
+        use super::u32_ as u32;
+        use super::u64_ as u64;
+        use super::bool_ as bool;
+        use super::{bool_ as str};
+        use super::char_ as char;
+    }
+}
+
+trait isize_ {
+    type isize;
+}
+
+fn usize<'usize>(usize: &'usize usize) -> &'usize usize { usize }
+
+mod reuse {
+    use std::mem::size_of;
+
+    type u8 = u64;
+    use std::string::String as i16;
+
+    pub fn check<u16>() {
+        assert_eq!(size_of::<u8>(), 8);
+        assert_eq!(size_of::<::u64>(), 0);
+        assert_eq!(size_of::<i16>(), 3 * size_of::<*const ()>());
+        assert_eq!(size_of::<u16>(), 0);
+    }
+}
+
+mod guard {
+    pub fn check() {
+        use std::u8; // bring module u8 in scope
+        fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
+            u8::max_value() // OK, resolves to associated function <u8>::max_value,
+                            // not to non-existent std::u8::max_value
+        }
+        assert_eq!(f(), u8::MAX); // OK, resolves to std::u8::MAX
+    }
+}
+
+fn main() {
+    let bool = true;
+    let _ = match bool {
+        str @ true => if str { i32 as i64 } else { i64 },
+        false => i64,
+    };
+
+    reuse::check::<u64>();
+    guard::check();
+}