Skip to content

Commit eac55c2

Browse files
committed
Rollup merge of rust-lang#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
2 parents a1e29da + b418cd2 commit eac55c2

File tree

3 files changed

+66
-113
lines changed

3 files changed

+66
-113
lines changed

src/librustc_resolve/diagnostics.rs

-45
Original file line numberDiff line numberDiff line change
@@ -205,51 +205,6 @@ about what constitutes an Item declaration and what does not:
205205
https://doc.rust-lang.org/reference.html#statements
206206
"##,
207207

208-
E0317: r##"
209-
User-defined types or type parameters cannot shadow the primitive types.
210-
This error indicates you tried to define a type, struct or enum with the same
211-
name as an existing primitive type:
212-
213-
```compile_fail
214-
struct u8 {
215-
// ...
216-
}
217-
```
218-
219-
To fix this, simply name it something else.
220-
221-
Such an error may also occur if you define a type parameter which shadows a
222-
primitive type. An example would be something like:
223-
224-
```compile_fail
225-
impl<u8> MyTrait for Option<u8> {
226-
// ...
227-
}
228-
```
229-
230-
In such a case, if you meant for `u8` to be a generic type parameter (i.e. any
231-
type can be used in its place), use something like `T` instead:
232-
233-
```ignore
234-
impl<T> MyTrait for Option<T> {
235-
// ...
236-
}
237-
```
238-
239-
On the other hand, if you wished to refer to the specific type `u8`, remove it
240-
from the type parameter list:
241-
242-
```ignore
243-
impl MyTrait for Option<u8> {
244-
// ...
245-
}
246-
247-
See the Types section of the reference for more information about the primitive
248-
types:
249-
250-
https://doc.rust-lang.org/reference.html#types
251-
"##,
252-
253208
E0364: r##"
254209
Private items cannot be publicly re-exported. This error indicates that you
255210
attempted to `pub use` a type or value that was not itself public.

src/librustc_resolve/lib.rs

+30-55
Original file line numberDiff line numberDiff line change
@@ -1619,15 +1619,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
16191619
intravisit::walk_crate(self, krate);
16201620
}
16211621

1622-
fn check_if_primitive_type_name(&self, name: Name, span: Span) {
1623-
if let Some(_) = self.primitive_type_table.primitive_types.get(&name) {
1624-
span_err!(self.session,
1625-
span,
1626-
E0317,
1627-
"user-defined types or type parameters cannot shadow the primitive types");
1628-
}
1629-
}
1630-
16311622
fn resolve_item(&mut self, item: &Item) {
16321623
let name = item.name;
16331624

@@ -1637,8 +1628,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
16371628
ItemEnum(_, ref generics) |
16381629
ItemTy(_, ref generics) |
16391630
ItemStruct(_, ref generics) => {
1640-
self.check_if_primitive_type_name(name, item.span);
1641-
16421631
self.with_type_parameter_rib(HasTypeParameters(generics, TypeSpace, ItemRibKind),
16431632
|this| intravisit::walk_item(this, item));
16441633
}
@@ -1659,8 +1648,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
16591648
}
16601649

16611650
ItemTrait(_, ref generics, ref bounds, ref trait_items) => {
1662-
self.check_if_primitive_type_name(name, item.span);
1663-
16641651
// Create a new rib for the trait-wide type parameters.
16651652
self.with_type_parameter_rib(HasTypeParameters(generics,
16661653
TypeSpace,
@@ -1695,8 +1682,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
16951682
});
16961683
}
16971684
hir::TypeTraitItem(..) => {
1698-
this.check_if_primitive_type_name(trait_item.name,
1699-
trait_item.span);
17001685
this.with_type_parameter_rib(NoTypeParameters, |this| {
17011686
intravisit::walk_trait_item(this, trait_item)
17021687
});
@@ -1720,28 +1705,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
17201705
}
17211706

17221707
ItemUse(ref view_path) => {
1723-
// check for imports shadowing primitive types
1724-
let check_rename = |this: &Self, id, name| {
1725-
match this.def_map.borrow().get(&id).map(|d| d.full_def()) {
1726-
Some(Def::Enum(..)) | Some(Def::TyAlias(..)) | Some(Def::Struct(..)) |
1727-
Some(Def::Trait(..)) | None => {
1728-
this.check_if_primitive_type_name(name, item.span);
1729-
}
1730-
_ => {}
1731-
}
1732-
};
1733-
17341708
match view_path.node {
1735-
hir::ViewPathSimple(name, _) => {
1736-
check_rename(self, item.id, name);
1737-
}
17381709
hir::ViewPathList(ref prefix, ref items) => {
1739-
for item in items {
1740-
if let Some(name) = item.node.rename() {
1741-
check_rename(self, item.node.id(), name);
1742-
}
1743-
}
1744-
17451710
// Resolve prefix of an import with empty braces (issue #28388)
17461711
if items.is_empty() && !prefix.segments.is_empty() {
17471712
match self.resolve_crate_relative_path(prefix.span,
@@ -1922,9 +1887,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
19221887
}
19231888

19241889
fn resolve_generics(&mut self, generics: &Generics) {
1925-
for type_parameter in generics.ty_params.iter() {
1926-
self.check_if_primitive_type_name(type_parameter.name, type_parameter.span);
1927-
}
19281890
for predicate in &generics.where_clause.predicates {
19291891
match predicate {
19301892
&hir::WherePredicate::BoundPredicate(_) |
@@ -2658,15 +2620,37 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
26582620

26592621
// Try to find a path to an item in a module.
26602622
let last_ident = segments.last().unwrap().identifier;
2661-
if segments.len() <= 1 {
2662-
let unqualified_def = self.resolve_identifier(last_ident, namespace, true);
2663-
return unqualified_def.and_then(|def| self.adjust_local_def(def, span))
2664-
.map(|def| {
2665-
PathResolution::new(def, path_depth)
2666-
});
2667-
}
2623+
// Resolve a single identifier with fallback to primitive types
2624+
let resolve_identifier_with_fallback = |this: &mut Self, record_used| {
2625+
let def = this.resolve_identifier(last_ident, namespace, record_used);
2626+
match def {
2627+
None | Some(LocalDef{def: Def::Mod(..), ..}) if namespace == TypeNS =>
2628+
this.primitive_type_table
2629+
.primitive_types
2630+
.get(&last_ident.unhygienic_name)
2631+
.map_or(def, |prim_ty| Some(LocalDef::from_def(Def::PrimTy(*prim_ty)))),
2632+
_ => def
2633+
}
2634+
};
26682635

2669-
let unqualified_def = self.resolve_identifier(last_ident, namespace, false);
2636+
if segments.len() == 1 {
2637+
// In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we
2638+
// don't report an error right away, but try to fallback to a primitive type.
2639+
// So, we are still able to successfully resolve something like
2640+
//
2641+
// use std::u8; // bring module u8 in scope
2642+
// fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
2643+
// u8::max_value() // OK, resolves to associated function <u8>::max_value,
2644+
// // not to non-existent std::u8::max_value
2645+
// }
2646+
//
2647+
// Such behavior is required for backward compatibility.
2648+
// The same fallback is used when `a` resolves to nothing.
2649+
let unqualified_def = resolve_identifier_with_fallback(self, true);
2650+
return unqualified_def.and_then(|def| self.adjust_local_def(def, span)).map(mk_res);
2651+
}
2652+
2653+
let unqualified_def = resolve_identifier_with_fallback(self, false);
26702654
let def = self.resolve_module_relative_path(span, segments, namespace);
26712655
match (def, unqualified_def) {
26722656
(Some(d), Some(ref ud)) if d == ud.def => {
@@ -2692,15 +2676,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
26922676
return Some(LocalDef::from_def(Def::Err));
26932677
}
26942678

2695-
// First, check to see whether the name is a primitive type.
2696-
if namespace == TypeNS {
2697-
if let Some(&prim_ty) = self.primitive_type_table
2698-
.primitive_types
2699-
.get(&identifier.unhygienic_name) {
2700-
return Some(LocalDef::from_def(Def::PrimTy(prim_ty)));
2701-
}
2702-
}
2703-
27042679
self.resolve_identifier_in_local_ribs(identifier, namespace, record_used)
27052680
}
27062681

src/test/compile-fail/issue-20427.rs renamed to src/test/run-pass/issue-20427.rs

+36-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -9,17 +9,17 @@
99
// except according to those terms.
1010

1111
// aux-build:i8.rs
12+
// ignore-pretty (#23623)
13+
1214
extern crate i8;
1315
use std::string as i16;
1416
static i32: i32 = 0;
1517
const i64: i64 = 0;
1618
fn u8(f32: f32) {}
1719
fn f<f64>(f64: f64) {}
18-
//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
19-
type u16 = u16; //~ ERROR user-defined types or type parameters cannot shadow the primitive types
20-
enum u32 {} //~ ERROR user-defined types or type parameters cannot shadow the primitive types
21-
struct u64; //~ ERROR user-defined types or type parameters cannot shadow the primitive types
22-
trait bool {} //~ ERROR user-defined types or type parameters cannot shadow the primitive types
20+
enum u32 {}
21+
struct u64;
22+
trait bool {}
2323

2424
mod char {
2525
extern crate i8;
@@ -40,29 +40,52 @@ mod char {
4040
use super::u8_ as u8;
4141
use super::f_ as f64;
4242
use super::u16_ as u16;
43-
//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
4443
use super::u32_ as u32;
45-
//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
4644
use super::u64_ as u64;
47-
//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
4845
use super::bool_ as bool;
49-
//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
5046
use super::{bool_ as str};
51-
//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
5247
use super::char_ as char;
5348
}
5449
}
5550

5651
trait isize_ {
57-
type isize; //~ ERROR user-defined types or type parameters cannot shadow the primitive types
52+
type isize;
5853
}
5954

6055
fn usize<'usize>(usize: &'usize usize) -> &'usize usize { usize }
6156

57+
mod reuse {
58+
use std::mem::size_of;
59+
60+
type u8 = u64;
61+
use std::string::String as i16;
62+
63+
pub fn check<u16>() {
64+
assert_eq!(size_of::<u8>(), 8);
65+
assert_eq!(size_of::<::u64>(), 0);
66+
assert_eq!(size_of::<i16>(), 3 * size_of::<*const ()>());
67+
assert_eq!(size_of::<u16>(), 0);
68+
}
69+
}
70+
71+
mod guard {
72+
pub fn check() {
73+
use std::u8; // bring module u8 in scope
74+
fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
75+
u8::max_value() // OK, resolves to associated function <u8>::max_value,
76+
// not to non-existent std::u8::max_value
77+
}
78+
assert_eq!(f(), u8::MAX); // OK, resolves to std::u8::MAX
79+
}
80+
}
81+
6282
fn main() {
6383
let bool = true;
64-
match bool {
84+
let _ = match bool {
6585
str @ true => if str { i32 as i64 } else { i64 },
6686
false => i64,
6787
};
88+
89+
reuse::check::<u64>();
90+
guard::check();
6891
}

0 commit comments

Comments
 (0)