diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index af8c9d816874..8efac52158ec 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2654,15 +2654,27 @@ 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); + 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 // OK, resolves to associated constant ::MAX, + // // not to non-existent std::u8::MAX + // } + // + // Such behavior is required for backward compatibility. + // The same fallback is used when `a` resolves to nothing. + let unqualified_def = self.resolve_identifier_with_fallback(last_ident, namespace, true); return unqualified_def.and_then(|def| self.adjust_local_def(def, span)) .map(|def| { PathResolution::new(def, path_depth) }); } - let unqualified_def = self.resolve_identifier(last_ident, namespace, false); + let unqualified_def = self.resolve_identifier_with_fallback(last_ident, namespace, false); let def = self.resolve_module_relative_path(span, segments, namespace); match (def, unqualified_def) { (Some(d), Some(ref ud)) if d == ud.def => { @@ -2678,6 +2690,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { def.map(mk_res) } + // Resolve a single identifier with fallback to primitive types + fn resolve_identifier_with_fallback(&mut self, + identifier: hir::Ident, + namespace: Namespace, + check_ribs: bool, + record_used: bool) + -> Option { + let def = self.resolve_identifier(identifier, namespace, check_ribs, record_used); + match def { + None | Some(LocalDef{def: Def::Mod(..), ..}) => { + if let Some(&prim_ty) = self.primitive_type_table + .primitive_types + .get(&identifier.unhygienic_name) { + Some(LocalDef::from_def(Def::PrimTy(prim_ty))) + } else { + def + } + } + _ => def + } + } + // Resolve a single identifier fn resolve_identifier(&mut self, identifier: hir::Ident, @@ -2688,15 +2722,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) } diff --git a/src/test/compile-fail/issue-20427.rs b/src/test/compile-fail/issue-20427.rs index 99dd22a888cb..7dedb9593e13 100644 --- a/src/test/compile-fail/issue-20427.rs +++ b/src/test/compile-fail/issue-20427.rs @@ -17,6 +17,7 @@ fn u8(f32: f32) {} fn f(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 +//~^ ERROR unsupported cyclic reference between types/traits detected 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