Rollup merge of #32131 - petrochenkov:prim, r=eddyb

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
This commit is contained in:
Manish Goregaokar 2016-03-26 09:07:20 +05:30
commit b8b17a54cf
3 changed files with 65 additions and 112 deletions

View File

@ -205,51 +205,6 @@ about what constitutes an Item declaration and what does not:
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.

View File

@ -1619,15 +1619,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
});
}
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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// 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
}
};
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 = self.resolve_identifier(last_ident, namespace, false);
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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
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)
}

View File

@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// 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.
//
@ -9,17 +9,17 @@
// 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) {}
//~^ 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
enum u32 {}
struct u64;
trait bool {}
mod char {
extern crate i8;
@ -40,29 +40,52 @@ mod char {
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
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;
match bool {
let _ = match bool {
str @ true => if str { i32 as i64 } else { i64 },
false => i64,
};
reuse::check::<u64>();
guard::check();
}