diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 39d0ed9a67b09..d113f6b5e4e76 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -77,7 +77,7 @@ pub struct LoweringContext<'a> { pub trait Resolver { // Resolve a global hir path generated by the lowerer when expanding `for`, `if let`, etc. - fn resolve_generated_global_path(&mut self, path: &mut hir::Path, is_value: bool); + fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool); // Obtain the resolution for a node id fn get_resolution(&mut self, id: NodeId) -> Option; @@ -2091,7 +2091,7 @@ impl<'a> LoweringContext<'a> { segments: segments.into(), }; - self.resolver.resolve_generated_global_path(&mut path, is_value); + self.resolver.resolve_hir_path(&mut path, is_value); path } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 7b73582449bfc..19764f2e68200 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -39,8 +39,6 @@ use self::ResolveResult::*; use self::FallbackSuggestion::*; use self::TypeParameters::*; use self::RibKind::*; -use self::UseLexicalScopeFlag::*; -use self::ModulePrefixResult::*; use rustc::hir::map::{Definitions, DefCollector}; use rustc::hir::{self, PrimTy, TyBool, TyChar, TyFloat, TyInt, TyUint, TyStr}; @@ -57,6 +55,7 @@ use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ast::{self, FloatTy}; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, Ident, SpannedIdent, IntTy, UintTy}; use syntax::ext::base::SyntaxExtension; +use syntax::ext::base::Determinacy::{Determined, Undetermined}; use syntax::symbol::{Symbol, keywords}; use syntax::util::lev_distance::find_best_match_for_name; @@ -191,10 +190,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, span: syntax_pos::Span, resolution_error: ResolutionError<'c>) -> DiagnosticBuilder<'a> { - if !resolver.emit_errors { - return resolver.session.diagnostic().struct_dummy(); - } - match resolution_error { ResolutionError::TypeParametersFromOuterFunction => { let mut err = struct_span_err!(resolver.session, @@ -584,8 +579,9 @@ impl<'a> Visitor for Resolver<'a> { self.resolve_type(ty); } fn visit_poly_trait_ref(&mut self, tref: &ast::PolyTraitRef, m: &ast::TraitBoundModifier) { - let def = - self.resolve_trait_reference(tref.trait_ref.ref_id, &tref.trait_ref.path, 0, None); + let ast::Path { ref segments, span, global } = tref.trait_ref.path; + let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); + let def = self.resolve_trait_reference(&path, global, None, span); self.record_def(tref.trait_ref.ref_id, def); visit::walk_poly_trait_ref(self, tref, m); } @@ -737,17 +733,6 @@ enum RibKind<'a> { MacroDefinition(Mark), } -#[derive(Copy, Clone)] -enum UseLexicalScopeFlag { - DontUseLexicalScope, - UseLexicalScope, -} - -enum ModulePrefixResult<'a> { - NoPrefixFound, - PrefixFound(Module<'a>, usize), -} - /// One local scope. #[derive(Debug)] struct Rib<'a> { @@ -765,33 +750,18 @@ impl<'a> Rib<'a> { } /// A definition along with the index of the rib it was found on +#[derive(Copy, Clone)] struct LocalDef { ribs: Option<(Namespace, usize)>, def: Def, } -impl LocalDef { - fn from_def(def: Def) -> Self { - LocalDef { - ribs: None, - def: def, - } - } -} - enum LexicalScopeBinding<'a> { Item(&'a NameBinding<'a>), - LocalDef(LocalDef), + Def(Def), } impl<'a> LexicalScopeBinding<'a> { - fn local_def(self) -> LocalDef { - match self { - LexicalScopeBinding::LocalDef(local_def) => local_def, - LexicalScopeBinding::Item(binding) => LocalDef::from_def(binding.def()), - } - } - fn item(self) -> Option<&'a NameBinding<'a>> { match self { LexicalScopeBinding::Item(binding) => Some(binding), @@ -800,6 +770,21 @@ impl<'a> LexicalScopeBinding<'a> { } } +#[derive(Copy, Clone)] +enum PathScope { + Global, + Lexical, + Import, +} + +#[derive(Clone)] +enum PathResult<'a> { + Module(Module<'a>), + NonModule(PathResolution), + Indeterminate, + Failed(String, bool /* is the error from the last segment? */), +} + enum ModuleKind { Block(NodeId), Def(Def, Name), @@ -1107,11 +1092,6 @@ pub struct Resolver<'a> { module_map: NodeMap>, extern_crate_roots: FxHashMap<(CrateNum, bool /* MacrosOnly? */), Module<'a>>, - // Whether or not to print error messages. Can be set to true - // when getting additional info for error message suggestions, - // so as to avoid printing duplicate errors - emit_errors: bool, - pub make_glob_map: bool, // Maps imports to the names of items actually imported (this actually maps // all imports, but only glob imports are actually interesting). @@ -1197,22 +1177,23 @@ impl<'a> ty::NodeIdTree for Resolver<'a> { } impl<'a> hir::lowering::Resolver for Resolver<'a> { - fn resolve_generated_global_path(&mut self, path: &mut hir::Path, is_value: bool) { + fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) { let namespace = if is_value { ValueNS } else { TypeNS }; - match self.resolve_crate_relative_path(path.span, &path.segments, namespace) { - Ok(binding) => path.def = binding.def(), - None => { - let path_name = &format!("{}", path); - let error = - ResolutionError::UnresolvedName { - path: path_name, - message: "", - context: UnresolvedNameContext::Other, - is_static_method: false, - is_field: false, - def: Def::Err, - }; - resolve_error(self, path.span, error); + let hir::Path { ref segments, span, global, ref mut def } = *path; + let path: Vec<_> = segments.iter().map(|seg| Ident::with_empty_ctxt(seg.name)).collect(); + let scope = if global { PathScope::Global } else { PathScope::Lexical }; + match self.resolve_path(&path, scope, Some(namespace), Some(span)) { + PathResult::Module(module) => *def = module.def().unwrap(), + PathResult::NonModule(path_res) if path_res.depth == 0 => *def = path_res.base_def, + PathResult::NonModule(..) => match self.resolve_path(&path, scope, None, Some(span)) { + PathResult::Failed(msg, _) => { + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + } + _ => {} + }, + PathResult::Indeterminate => unreachable!(), + PathResult::Failed(msg, _) => { + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); } } } @@ -1230,22 +1211,6 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { } } -trait Named { - fn ident(&self) -> Ident; -} - -impl Named for ast::PathSegment { - fn ident(&self) -> Ident { - self.identifier - } -} - -impl Named for hir::PathSegment { - fn ident(&self) -> Ident { - Ident::with_empty_ctxt(self.name) - } -} - impl<'a> Resolver<'a> { pub fn new(session: &'a Session, krate: &Crate, @@ -1307,7 +1272,6 @@ impl<'a> Resolver<'a> { module_map: module_map, extern_crate_roots: FxHashMap(), - emit_errors: true, make_glob_map: make_glob_map == MakeGlobMap::Yes, glob_map: NodeMap(), @@ -1413,163 +1377,6 @@ impl<'a> Resolver<'a> { } } - fn expect_module(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Option) - -> ResolveResult> { - match binding.module() { - Ok(module) => Success(module), - Err(true) => Failed(None), - Err(false) => { - let msg = format!("Not a module `{}`", name); - Failed(span.map(|span| (span, msg))) - } - } - } - - /// Resolves the given module path from the given root `search_module`. - fn resolve_module_path_from_root(&mut self, - mut search_module: Module<'a>, - module_path: &[Ident], - index: usize, - span: Option) - -> ResolveResult> { - fn search_parent_externals<'a>(this: &mut Resolver<'a>, needle: Name, module: Module<'a>) - -> Option> { - match this.resolve_name_in_module(module, needle, TypeNS, false, None) { - Success(binding) if binding.is_extern_crate() => Some(module), - _ => if let (&ModuleKind::Def(..), Some(parent)) = (&module.kind, module.parent) { - search_parent_externals(this, needle, parent) - } else { - None - }, - } - } - - let mut index = index; - let module_path_len = module_path.len(); - - // Resolve the module part of the path. This does not involve looking - // upward though scope chains; we simply resolve names directly in - // modules as we go. - while index < module_path_len { - let name = module_path[index].name; - match self.resolve_name_in_module(search_module, name, TypeNS, false, span) { - Failed(_) => { - let module_name = module_to_string(search_module); - let msg = if "???" == &module_name { - let current_module = self.current_module; - match search_parent_externals(self, name, current_module) { - Some(module) => { - let path_str = names_to_string(module_path); - let target_mod_str = module_to_string(&module); - let current_mod_str = module_to_string(current_module); - - let prefix = if target_mod_str == current_mod_str { - "self::".to_string() - } else { - format!("{}::", target_mod_str) - }; - - format!("Did you mean `{}{}`?", prefix, path_str) - } - None => format!("Maybe a missing `extern crate {};`?", name), - } - } else { - format!("Could not find `{}` in `{}`", name, module_name) - }; - - return Failed(span.map(|span| (span, msg))); - } - Indeterminate => { - debug!("(resolving module path for import) module resolution is \ - indeterminate: {}", - name); - return Indeterminate; - } - Success(binding) => { - // Check to see whether there are type bindings, and, if - // so, whether there is a module within. - match self.expect_module(name, binding, span) { - Success(module) => search_module = module, - result @ _ => return result, - } - } - } - - index += 1; - } - - return Success(search_module); - } - - /// Attempts to resolve the module part of an import directive or path - /// rooted at the given module. - fn resolve_module_path(&mut self, - module_path: &[Ident], - use_lexical_scope: UseLexicalScopeFlag, - span: Option) - -> ResolveResult> { - if module_path.len() == 0 { - return Success(self.graph_root) // Use the crate root - } - - debug!("(resolving module path for import) processing `{}` rooted at `{}`", - names_to_string(module_path), - module_to_string(self.current_module)); - - // Resolve the module prefix, if any. - let module_prefix_result = self.resolve_module_prefix(module_path, span); - - let search_module; - let start_index; - match module_prefix_result { - Failed(err) => return Failed(err), - Indeterminate => { - debug!("(resolving module path for import) indeterminate; bailing"); - return Indeterminate; - } - Success(NoPrefixFound) => { - // There was no prefix, so we're considering the first element - // of the path. How we handle this depends on whether we were - // instructed to use lexical scope or not. - match use_lexical_scope { - DontUseLexicalScope => { - // This is a crate-relative path. We will start the - // resolution process at index zero. - search_module = self.graph_root; - start_index = 0; - } - UseLexicalScope => { - // This is not a crate-relative path. We resolve the - // first component of the path in the current lexical - // scope and then proceed to resolve below that. - let ident = module_path[0]; - let lexical_binding = - self.resolve_ident_in_lexical_scope(ident, TypeNS, span); - if let Some(binding) = lexical_binding.and_then(LexicalScopeBinding::item) { - match self.expect_module(ident.name, binding, span) { - Success(containing_module) => { - search_module = containing_module; - start_index = 1; - } - result @ _ => return result, - } - } else { - let msg = - format!("Use of undeclared type or module `{}`", ident.name); - return Failed(span.map(|span| (span, msg))); - } - } - } - } - Success(PrefixFound(ref containing_module, index)) => { - search_module = containing_module; - start_index = index; - } - } - - self.resolve_module_path_from_root(search_module, module_path, start_index, span) - } - /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. /// More specifically, we proceed up the hierarchy of scopes and return the binding for /// `ident` in the first scope that defines it (or None if no scopes define it). @@ -1600,9 +1407,10 @@ impl<'a> Resolver<'a> { for i in (0 .. self.ribs[ns].len()).rev() { if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() { // The ident resolves to a type parameter or local variable. - return Some(LexicalScopeBinding::LocalDef(LocalDef { - ribs: Some((ns, i)), - def: def, + return Some(LexicalScopeBinding::Def(if let Some(span) = record_used { + self.adjust_local_def(LocalDef { ribs: Some((ns, i)), def: def }, span) + } else { + def })); } @@ -1637,45 +1445,6 @@ impl<'a> Resolver<'a> { None } - /// Resolves a "module prefix". A module prefix is one or both of (a) `self::`; - /// (b) some chain of `super::`. - /// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) * - fn resolve_module_prefix(&mut self, module_path: &[Ident], span: Option) - -> ResolveResult> { - if module_path[0].name == "$crate" { - return Success(PrefixFound(self.resolve_crate_var(module_path[0].ctxt), 1)); - } - - // Start at the current module if we see `self` or `super`, or at the - // top of the crate otherwise. - let mut i = match &*module_path[0].name.as_str() { - "self" => 1, - "super" => 0, - _ => return Success(NoPrefixFound), - }; - - let mut containing_module = - self.module_map[&self.current_module.normal_ancestor_id.unwrap()]; - - // Now loop through all the `super`s we find. - while i < module_path.len() && module_path[i].name == "super" { - debug!("(resolving module prefix) resolving `super` at {}", - module_to_string(&containing_module)); - if let Some(parent) = containing_module.parent { - containing_module = self.module_map[&parent.normal_ancestor_id.unwrap()]; - i += 1; - } else { - let msg = "There are too many initial `super`s.".into(); - return Failed(span.map(|span| (span, msg))); - } - } - - debug!("(resolving module prefix) finished resolving prefix at {}", - module_to_string(&containing_module)); - - return Success(PrefixFound(containing_module, i)); - } - fn resolve_crate_var(&mut self, mut crate_var_ctxt: SyntaxContext) -> Module<'a> { while crate_var_ctxt.source().0 != SyntaxContext::empty() { crate_var_ctxt = crate_var_ctxt.source().0; @@ -1834,23 +1603,32 @@ impl<'a> Resolver<'a> { ItemKind::Use(ref view_path) => { match view_path.node { ast::ViewPathList(ref prefix, ref items) => { + let path: Vec<_> = + prefix.segments.iter().map(|seg| seg.identifier).collect(); // 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, - &prefix.segments, - TypeNS) { - Some(binding) => { - let def = binding.def(); - self.record_def(item.id, PathResolution::new(def)); - } - None => { - resolve_error(self, - prefix.span, - ResolutionError::FailedToResolve( - &path_names_to_string(prefix, 0))); - self.record_def(item.id, err_path_resolution()); + let (scope, span) = (PathScope::Import, prefix.span); + // FIXME(#38012) This should be a module path, not anything in TypeNS. + let result = + self.resolve_path(&path, scope, Some(TypeNS), Some(span)); + let (def, msg) = match result { + PathResult::Module(module) => (module.def().unwrap(), None), + PathResult::NonModule(res) if res.depth == 0 => + (res.base_def, None), + PathResult::NonModule(_) => { + // Resolve a module path for better errors + match self.resolve_path(&path, scope, None, Some(span)) { + PathResult::Failed(msg, _) => (Def::Err, Some(msg)), + _ => unreachable!(), + } } + PathResult::Indeterminate => unreachable!(), + PathResult::Failed(msg, _) => (Def::Err, Some(msg)), + }; + if let Some(msg) = msg { + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); } + self.record_def(item.id, PathResolution::new(def)); } } _ => {} @@ -1925,60 +1703,51 @@ impl<'a> Resolver<'a> { } fn resolve_trait_reference(&mut self, - id: NodeId, - trait_path: &Path, - path_depth: usize, - generics: Option<&Generics>) + path: &[Ident], + global: bool, + generics: Option<&Generics>, + span: Span) -> PathResolution { - if let Some(path_res) = self.resolve_path(id, trait_path, path_depth, TypeNS) { - match path_res.base_def { - Def::Trait(_) => { - debug!("(resolving trait) found trait def: {:?}", path_res); - return path_res; - } - Def::Err => return err_path_resolution(), - _ => {} + let scope = if global { PathScope::Global } else { PathScope::Lexical }; + let def = match self.resolve_path(path, scope, None, Some(span)) { + PathResult::Module(module) => Some(module.def().unwrap()), + PathResult::NonModule(..) => return err_path_resolution(), + PathResult::Failed(msg, false) => { + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + return err_path_resolution(); + } + _ => match self.resolve_path(path, scope, Some(TypeNS), None) { + PathResult::NonModule(path_resolution) => Some(path_resolution.base_def), + _ => None, + }, + }; + + if let Some(def) = def { + if let Def::Trait(_) = def { + return PathResolution::new(def); } - let mut err = resolve_struct_error(self, trait_path.span, { - ResolutionError::IsNotATrait(&path_names_to_string(trait_path, path_depth), - path_res.base_def.kind_name()) + let mut err = resolve_struct_error(self, span, { + ResolutionError::IsNotATrait(&names_to_string(path), def.kind_name()) }); if let Some(generics) = generics { - if let Some(span) = generics.span_for_name( - &path_names_to_string(trait_path, path_depth)) { - + if let Some(span) = generics.span_for_name(&names_to_string(path)) { err.span_label(span, &"type parameter defined here"); } } // If it's a typedef, give a note - if let Def::TyAlias(..) = path_res.base_def { + if let Def::TyAlias(..) = def { err.note(&format!("type aliases cannot be used for traits")); } err.emit(); } else { // find possible candidates - let trait_name = trait_path.segments.last().unwrap().identifier.name; - let candidates = - self.lookup_candidates( - trait_name, - TypeNS, - |def| match def { - Def::Trait(_) => true, - _ => false, - }, - ); - - // create error object - let name = &path_names_to_string(trait_path, path_depth); - let error = - ResolutionError::UndeclaredTraitName( - name, - candidates, - ); + let is_trait = |def| match def { Def::Trait(_) => true, _ => false }; + let candidates = self.lookup_candidates(path.last().unwrap().name, TypeNS, is_trait); - resolve_error(self, trait_path.span, error); + let path = names_to_string(path); + resolve_error(self, span, ResolutionError::UndeclaredTraitName(&path, candidates)); } err_path_resolution() } @@ -2003,8 +1772,9 @@ impl<'a> Resolver<'a> { let mut new_val = None; let mut new_id = None; if let Some(trait_ref) = opt_trait_ref { - let path_res = - self.resolve_trait_reference(trait_ref.ref_id, &trait_ref.path, 0, generics); + let ast::Path { ref segments, span, global } = trait_ref.path; + let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); + let path_res = self.resolve_trait_reference(&path, global, generics, span); assert!(path_res.depth == 0); self.record_def(trait_ref.ref_id, path_res); if path_res.base_def != Def::Err { @@ -2265,8 +2035,7 @@ impl<'a> Resolver<'a> { self.record_def(ty.id, err_path_resolution()); // Keep reporting some errors even if they're ignored above. - let result = self.resolve_path(ty.id, path, 0, TypeNS); - if result.map(|resolution| resolution.base_def) != Some(Def::Err) { + { let kind = if maybe_qself.is_some() { "associated type" } else { @@ -2408,13 +2177,8 @@ impl<'a> Resolver<'a> { resolution } } else { - if self.resolve_path(pat_id, path, 0, namespace).is_none() { - resolve_error( - self, - path.span, - ResolutionError::PatPathUnresolved(expected_what, path) - ); - } + let error = ResolutionError::PatPathUnresolved(expected_what, path); + resolve_error(self, path.span, error); err_path_resolution() }; @@ -2526,81 +2290,32 @@ impl<'a> Resolver<'a> { id: NodeId, maybe_qself: Option<&QSelf>, path: &Path, - namespace: Namespace) + ns: Namespace) -> Option { - let max_assoc_types; - - match maybe_qself { - Some(qself) => { - if qself.position == 0 { - // FIXME: Create some fake resolution that can't possibly be a type. - return Some(PathResolution { - base_def: Def::Mod(self.definitions.local_def_id(ast::CRATE_NODE_ID)), - depth: path.segments.len(), - }); - } - max_assoc_types = path.segments.len() - qself.position; - // Make sure the trait is valid. - self.resolve_trait_reference(id, path, max_assoc_types, None); - } - None => { - max_assoc_types = path.segments.len(); - } - } - - let mut resolution = self.with_no_errors(|this| { - this.resolve_path(id, path, 0, namespace) - }); - if resolution.map(|res| res.base_def) == Some(Def::Err) { resolution = None; } - for depth in 1..max_assoc_types { - if resolution.is_some() { - break; + let ast::Path { ref segments, global, span } = *path; + let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); + let scope = if global { PathScope::Global } else { PathScope::Lexical }; + + if let Some(qself) = maybe_qself { + if qself.position == 0 { + // FIXME: Create some fake resolution that can't possibly be a type. + return Some(PathResolution { + base_def: Def::Mod(self.definitions.local_def_id(ast::CRATE_NODE_ID)), + depth: path.len(), + }); } - self.with_no_errors(|this| { - let partial_resolution = this.resolve_path(id, path, depth, TypeNS); - if let Some(Def::Mod(..)) = partial_resolution.map(|r| r.base_def) { - // Modules cannot have associated items - } else { - resolution = partial_resolution; - if resolution.map(|res| res.base_def) == Some(Def::Err) { resolution = None; } - } - }); + // Make sure the trait is valid. + self.resolve_trait_reference(&path[..qself.position], global, None, span); } - resolution - } - - /// Skips `path_depth` trailing segments, which is also reflected in the - /// returned value. See `hir::def::PathResolution` for more info. - fn resolve_path(&mut self, id: NodeId, path: &Path, path_depth: usize, namespace: Namespace) - -> Option { - debug!("resolve_path(id={:?} path={:?}, path_depth={:?})", id, path, path_depth); - let span = path.span; - let segments = &path.segments[..path.segments.len() - path_depth]; - - let mk_res = |def| PathResolution { base_def: def, depth: path_depth }; - - if path.global { - let binding = self.resolve_crate_relative_path(span, segments, namespace); - return binding.map(|binding| mk_res(binding.def())); - } - - // Try to find a path to an item in a module. - let last_ident = segments.last().unwrap().identifier; - // 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.name) - .map_or(def, |prim_ty| Some(LocalDef::from_def(Def::PrimTy(*prim_ty)))), - _ => def + let result = match self.resolve_path(&path, scope, Some(ns), Some(span)) { + PathResult::NonModule(path_res) => match path_res.base_def { + Def::Trait(..) if maybe_qself.is_some() => return None, + _ => path_res, + }, + PathResult::Module(module) if !module.is_normal() => { + PathResolution::new(module.def().unwrap()) } - }; - - 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 @@ -2613,39 +2328,140 @@ impl<'a> Resolver<'a> { // // Such behavior is required for backward compatibility. // The same fallback is used when `a` resolves to nothing. - let def = resolve_identifier_with_fallback(self, Some(span)); - return def.map(|def| mk_res(self.adjust_local_def(def, span))); + _ if self.primitive_type_table.primitive_types.contains_key(&path[0].name) => { + PathResolution { + base_def: Def::PrimTy(self.primitive_type_table.primitive_types[&path[0].name]), + depth: segments.len() - 1, + } + } + PathResult::Module(module) => PathResolution::new(module.def().unwrap()), + PathResult::Failed(msg, false) => { + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + err_path_resolution() + } + _ => return None, + }; + + if path.len() == 1 || result.base_def == Def::Err { + return Some(result); } - let unqualified_def = resolve_identifier_with_fallback(self, None); - let qualified_binding = self.resolve_module_relative_path(span, segments, namespace); - match (qualified_binding, unqualified_def) { - (Some(binding), Some(ref ud)) if binding.def() == ud.def && - segments[0].identifier.name != "$crate" => { - self.session - .add_lint(lint::builtin::UNUSED_QUALIFICATIONS, - id, - span, - "unnecessary qualification".to_string()); + let unqualified_result = { + match self.resolve_path(&[*path.last().unwrap()], PathScope::Lexical, Some(ns), None) { + PathResult::NonModule(path_res) => path_res.base_def, + PathResult::Module(module) => module.def().unwrap(), + _ => return Some(result), } - _ => {} + }; + if result.base_def == unqualified_result && path[0].name != "$crate" { + let lint = lint::builtin::UNUSED_QUALIFICATIONS; + self.session.add_lint(lint, id, span, "unnecessary qualification".to_string()); } - qualified_binding.map(|binding| mk_res(binding.def())) + Some(result) } - // Resolve a single identifier - fn resolve_identifier(&mut self, - identifier: Ident, - namespace: Namespace, - record_used: Option) - -> Option { - if identifier.name == keywords::Invalid.name() { - return None; + fn resolve_path(&mut self, + path: &[Ident], + scope: PathScope, + opt_ns: Option, // `None` indicates a module path + record_used: Option) + -> PathResult<'a> { + let (mut module, allow_self) = match scope { + PathScope::Lexical => (None, true), + PathScope::Import => (Some(self.graph_root), true), + PathScope::Global => (Some(self.graph_root), false), + }; + let mut allow_super = allow_self; + + for (i, &ident) in path.iter().enumerate() { + let is_last = i == path.len() - 1; + let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; + + if i == 0 && allow_self && ns == TypeNS && ident.name == keywords::SelfValue.name() { + module = Some(self.module_map[&self.current_module.normal_ancestor_id.unwrap()]); + continue + } else if i == 0 && allow_self && ns == TypeNS && ident.name == "$crate" { + module = Some(self.resolve_crate_var(ident.ctxt)); + continue + } else if allow_super && ns == TypeNS && ident.name == keywords::Super.name() { + let current_module = if i == 0 { self.current_module } else { module.unwrap() }; + let self_module = self.module_map[¤t_module.normal_ancestor_id.unwrap()]; + if let Some(parent) = self_module.parent { + module = Some(self.module_map[&parent.normal_ancestor_id.unwrap()]); + continue + } else { + let msg = "There are too many initial `super`s.".to_string(); + return PathResult::Failed(msg, false); + } + } + allow_super = false; + + let binding = if let Some(module) = module { + match self.resolve_name_in_module(module, ident.name, ns, false, record_used) { + Success(binding) => Ok(binding), + Indeterminate => Err(Undetermined), + Failed(_) => Err(Determined), + } + } else { + match self.resolve_ident_in_lexical_scope(ident, ns, record_used) { + Some(LexicalScopeBinding::Item(binding)) => Ok(binding), + Some(LexicalScopeBinding::Def(def)) if opt_ns.is_some() => { + return PathResult::NonModule(PathResolution { + base_def: def, + depth: path.len() - 1, + }); + } + _ => Err(if record_used.is_some() { Determined } else { Undetermined }), + } + }; + + match binding { + Ok(binding) => { + if let Ok(next_module) = binding.module() { + module = Some(next_module); + } else if binding.def() == Def::Err { + return PathResult::NonModule(err_path_resolution()); + } else if opt_ns.is_some() { + return PathResult::NonModule(PathResolution { + base_def: binding.def(), + depth: path.len() - i - 1, + }); + } else { + return PathResult::Failed(format!("Not a module `{}`", ident), is_last); + } + } + Err(Undetermined) => return PathResult::Indeterminate, + Err(Determined) => { + if let Some(module) = module { + if opt_ns.is_some() && !module.is_normal() { + return PathResult::NonModule(PathResolution { + base_def: module.def().unwrap(), + depth: path.len() - i, + }); + } + } + let msg = if module.and_then(ModuleS::def) == self.graph_root.def() { + let is_mod = |def| match def { Def::Mod(..) => true, _ => false }; + let mut candidates = + self.lookup_candidates(ident.name, TypeNS, is_mod).candidates; + candidates.sort_by_key(|path| (path.segments.len(), path.to_string())); + if let Some(candidate) = candidates.get(0) { + format!("Did you mean `{}`?", candidate) + } else { + format!("Maybe a missing `extern crate {};`?", ident) + } + } else if i == 0 { + format!("Use of undeclared type or module `{}`", ident) + } else { + format!("Could not find `{}` in `{}`", ident, path[i - 1]) + }; + return PathResult::Failed(msg, is_last); + } + } } - self.resolve_ident_in_lexical_scope(identifier, namespace, record_used) - .map(LexicalScopeBinding::local_def) + PathResult::Module(module.unwrap()) } // Resolve a local definition, potentially adjusting for closures. @@ -2736,65 +2552,6 @@ impl<'a> Resolver<'a> { return def; } - // resolve a "module-relative" path, e.g. a::b::c - fn resolve_module_relative_path(&mut self, - span: Span, - segments: &[ast::PathSegment], - namespace: Namespace) - -> Option<&'a NameBinding<'a>> { - let module_path = - segments.split_last().unwrap().1.iter().map(|ps| ps.identifier).collect::>(); - - let module = match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) { - Failed(err) => { - if let Some((span, msg)) = err { - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); - } - return Some(self.dummy_binding); - } - Indeterminate => return None, - Success(module) => module, - }; - - let name = segments.last().unwrap().identifier.name; - self.resolve_name_in_module(module, name, namespace, false, Some(span)).success() - } - - /// Invariant: This must be called only during main resolution, not during - /// import resolution. - fn resolve_crate_relative_path(&mut self, span: Span, segments: &[T], namespace: Namespace) - -> Option<&'a NameBinding<'a>> - where T: Named, - { - let module_path = segments.split_last().unwrap().1.iter().map(T::ident).collect::>(); - let root = self.graph_root; - - let module = match self.resolve_module_path_from_root(root, &module_path, 0, Some(span)) { - Failed(err) => { - if let Some((span, msg)) = err { - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); - } - return Some(self.dummy_binding); - } - - Indeterminate => return None, - - Success(module) => module, - }; - - let name = segments.last().unwrap().ident().name; - self.resolve_name_in_module(module, name, namespace, false, Some(span)).success() - } - - fn with_no_errors(&mut self, f: F) -> T - where F: FnOnce(&mut Resolver) -> T - { - self.emit_errors = false; - let rs = f(self); - self.emit_errors = true; - rs - } - // Calls `f` with a `Resolver` whose current lexical scope is `module`'s lexical scope, // i.e. the module's items and the prelude (unless the module is `#[no_implicit_prelude]`). // FIXME #34673: This needs testing. @@ -2918,11 +2675,7 @@ impl<'a> Resolver<'a> { let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?", path_name); - if self.emit_errors { - err.help(&msg); - } else { - err.span_help(expr.span, &msg); - } + err.help(&msg); err.emit(); self.record_def(expr.id, err_path_resolution()); } else { @@ -2943,9 +2696,13 @@ impl<'a> Resolver<'a> { } else { // Be helpful if the name refers to a struct let path_name = path_names_to_string(path, 0); - let type_res = self.with_no_errors(|this| { - this.resolve_path(expr.id, path, 0, TypeNS) - }); + let ast::Path { ref segments, global, .. } = *path; + let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); + let scope = if global { PathScope::Global } else { PathScope::Lexical }; + let type_res = match self.resolve_path(&path, scope, Some(TypeNS), None) { + PathResult::NonModule(type_res) => Some(type_res), + _ => None, + }; self.record_def(expr.id, err_path_resolution()); @@ -2957,16 +2714,11 @@ impl<'a> Resolver<'a> { let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?", path_name); - if self.emit_errors { - err.help(&msg); - } else { - err.span_help(expr.span, &msg); - } + err.help(&msg); err.emit(); } else { // Keep reporting some errors even if they're ignored above. - let result = self.resolve_path(expr.id, path, 0, ValueNS); - if result.map(|resolution| resolution.base_def) != Some(Def::Err) { + { let mut method_scope = false; let mut is_static = false; self.ribs[ValueNS].iter().rev().all(|rib| { @@ -2986,7 +2738,7 @@ impl<'a> Resolver<'a> { expr.span, ResolutionError::SelfNotAvailableInStaticMethod); } else { - let last_name = path.segments.last().unwrap().identifier.name; + let last_name = path.last().unwrap().name; let (mut msg, is_field) = match self.find_fallback_in_self_type(last_name) { NoSuggestion => { @@ -3018,16 +2770,9 @@ impl<'a> Resolver<'a> { msg = format!("did you mean {}?", msg); } else { // we display a help message if this is a module - let name_path: Vec<_> = - path.segments.iter().map(|seg| seg.identifier).collect(); - - match self.resolve_module_path(&name_path[..], - UseLexicalScope, - Some(expr.span)) { - Success(e) => { - if let Some(def_type) = e.def() { - def = def_type; - } + match self.resolve_path(&path, scope, None, None) { + PathResult::Module(module) => { + def = module.def().unwrap(); context = UnresolvedNameContext::PathIsMod(parent); }, _ => {}, @@ -3270,7 +3015,7 @@ impl<'a> Resolver<'a> { segms.push(segment); let path = Path { span: span, - global: true, + global: false, segments: segms, }; // the entity is accessible in the following cases: @@ -3320,34 +3065,32 @@ impl<'a> Resolver<'a> { } fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility { - let (path, id) = match *vis { + let (segments, span, id) = match *vis { ast::Visibility::Public => return ty::Visibility::Public, ast::Visibility::Crate(_) => return ty::Visibility::Restricted(ast::CRATE_NODE_ID), - ast::Visibility::Restricted { ref path, id } => (path, id), + ast::Visibility::Restricted { ref path, id } => (&path.segments, path.span, id), ast::Visibility::Inherited => { return ty::Visibility::Restricted(self.current_module.normal_ancestor_id.unwrap()); } }; - let segments: Vec<_> = path.segments.iter().map(|seg| seg.identifier).collect(); + let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); let mut path_resolution = err_path_resolution(); - let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, Some(path.span)) { - Success(module) => { + let vis = match self.resolve_path(&path, PathScope::Import, None, Some(span)) { + PathResult::Module(module) => { path_resolution = PathResolution::new(module.def().unwrap()); ty::Visibility::Restricted(module.normal_ancestor_id.unwrap()) } - Indeterminate => unreachable!(), - Failed(err) => { - if let Some((span, msg)) = err { - self.session.span_err(span, &format!("failed to resolve module path. {}", msg)); - } + PathResult::Failed(msg, _) => { + self.session.span_err(span, &format!("failed to resolve module path. {}", msg)); ty::Visibility::Public } + _ => ty::Visibility::Public, }; self.def_map.insert(id, path_resolution); if !self.is_accessible(vis) { let msg = format!("visibilities can only be restricted to ancestor modules"); - self.session.span_err(path.span, &msg); + self.session.span_err(span, &msg); } vis } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 5c9e8bb93718a..c30154b9bba64 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -12,11 +12,10 @@ use self::ImportDirectiveSubclass::*; use {Module, PerNS}; use Namespace::{self, TypeNS, MacroNS}; -use {NameBinding, NameBindingKind, PrivacyError, ToNameBinding}; +use {NameBinding, NameBindingKind, PathResult, PathScope, PrivacyError, ToNameBinding}; use ResolveResult; use ResolveResult::*; use Resolver; -use UseLexicalScopeFlag::DontUseLexicalScope; use {names_to_string, module_to_string}; use {resolve_error, ResolutionError}; @@ -27,6 +26,7 @@ use rustc::hir::def::*; use syntax::ast::{Ident, NodeId, Name}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::hygiene::Mark; +use syntax::symbol::keywords; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; @@ -482,14 +482,13 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // For better failure detection, pretend that the import will not define any names // while resolving its module path. directive.vis.set(ty::Visibility::PrivateExternal); - let result = - self.resolve_module_path(&directive.module_path, DontUseLexicalScope, None); + let result = self.resolve_path(&directive.module_path, PathScope::Import, None, None); directive.vis.set(vis); match result { - Success(module) => module, - Indeterminate => return Indeterminate, - Failed(err) => return Failed(err), + PathResult::Module(module) => module, + PathResult::Indeterminate => return Indeterminate, + _ => return Failed(None), } }; @@ -551,21 +550,20 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.current_module = directive.parent; let ImportDirective { ref module_path, span, .. } = *directive; - let module_result = self.resolve_module_path(&module_path, DontUseLexicalScope, Some(span)); + let module_result = self.resolve_path(&module_path, PathScope::Import, None, Some(span)); let module = match module_result { - Success(module) => module, - Indeterminate => return Indeterminate, - Failed(err) => { - let self_module = self.module_map[&self.current_module.normal_ancestor_id.unwrap()]; - - let resolve_from_self_result = self.resolve_module_path_from_root( - &self_module, &module_path, 0, Some(span)); - - return if let Success(_) = resolve_from_self_result { + PathResult::Module(module) => module, + PathResult::NonModule(..) => return Success(()), + PathResult::Indeterminate => return Indeterminate, + PathResult::Failed(msg, _) => { + let mut path = vec![keywords::SelfValue.ident()]; + path.extend(module_path); + let result = self.resolve_path(&path, PathScope::Import, None, None); + return if let PathResult::Module(..) = result { let msg = format!("Did you mean `self::{}`?", &names_to_string(module_path)); Failed(Some((span, msg))) } else { - Failed(err) + Failed(Some((span, msg))) }; }, }; diff --git a/src/test/compile-fail/issue-28388-1.rs b/src/test/compile-fail/issue-28388-1.rs index ef97b400b00a5..bee05cd53133a 100644 --- a/src/test/compile-fail/issue-28388-1.rs +++ b/src/test/compile-fail/issue-28388-1.rs @@ -10,6 +10,6 @@ // Prefix in imports with empty braces should be resolved and checked privacy, stability, etc. -use foo::{}; //~ ERROR failed to resolve. foo +use foo::{}; //~ ERROR failed to resolve. Maybe a missing `extern crate foo;`? fn main() {}