diff options
| author | Jeffrey Seyfried <jeffrey.seyfried@gmail.com> | 2016-03-12 08:03:13 +0000 |
|---|---|---|
| committer | Jeffrey Seyfried <jeffrey.seyfried@gmail.com> | 2016-03-26 18:22:42 +0000 |
| commit | 73417853e40646406a82ea39e606fb6199fa6b5d (patch) | |
| tree | e0cdb52993fc238971eba39aa06bd2ba61d5ea87 | |
| parent | 07fecf80980c8df846bc63a29ca712b18fdbcfa7 (diff) | |
| download | rust-73417853e40646406a82ea39e606fb6199fa6b5d.tar.gz rust-73417853e40646406a82ea39e606fb6199fa6b5d.zip | |
Refactor out the common functionality of
`resolve_item_in_lexical_scope` and `resolve_identifier_in_local_ribs` into a new function `resolve_ident_in_lexical_scope`.
| -rw-r--r-- | src/librustc_resolve/lib.rs | 113 |
1 files changed, 61 insertions, 52 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index df2caa02812..67279207e5b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -784,6 +784,11 @@ impl LocalDef { } } +enum LexicalScopeBinding<'a> { + Item(&'a NameBinding<'a>), + LocalDef(LocalDef), +} + /// The link from a module up to its nearest parent node. #[derive(Clone,Debug)] enum ParentLink<'a> { @@ -1430,40 +1435,66 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { span) } - /// This function resolves `name` in `namespace` in the current lexical scope, returning - /// Success(binding) if `name` resolves to an item, or Failed(None) if `name` does not resolve - /// or resolves to a type parameter or local variable. - /// n.b. `resolve_identifier_in_local_ribs` also resolves names in the current lexical scope. + /// 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). + /// + /// A block's items are above its local variables in the scope hierarchy, regardless of where + /// the items are defined in the block. For example, + /// ```rust + /// fn f() { + /// g(); // Since there are no local variables in scope yet, this resolves to the item. + /// let g = || {}; + /// fn g() {} + /// g(); // This resolves to the local variable `g` since it shadows the item. + /// } + /// ``` /// /// Invariant: This must only be called during main resolution, not during /// import resolution. - fn resolve_item_in_lexical_scope(&mut self, - name: Name, - namespace: Namespace, - record_used: bool) - -> ResolveResult<&'a NameBinding<'a>> { + fn resolve_ident_in_lexical_scope(&mut self, + ident: hir::Ident, + ns: Namespace, + record_used: bool) + -> Option<LexicalScopeBinding<'a>> { + let name = match ns { ValueNS => ident.name, TypeNS => ident.unhygienic_name }; + // Walk backwards up the ribs in scope. - for i in (0 .. self.get_ribs(namespace).len()).rev() { - if let Some(_) = self.get_ribs(namespace)[i].bindings.get(&name).cloned() { - // The name resolves to a type parameter or local variable, so return Failed(None). - return Failed(None); - } - - if let ModuleRibKind(module) = self.get_ribs(namespace)[i].kind { - if let Success(binding) = self.resolve_name_in_module(module, - name, - namespace, - true, - record_used) { - // The name resolves to an item. - return Success(binding); + for i in (0 .. self.get_ribs(ns).len()).rev() { + if let Some(def) = self.get_ribs(ns)[i].bindings.get(&name).cloned() { + // The ident resolves to a type parameter or local variable. + return Some(LexicalScopeBinding::LocalDef(LocalDef { + ribs: Some((ns, i)), + def: def, + })); + } + + if let ModuleRibKind(module) = self.get_ribs(ns)[i].kind { + let name = ident.unhygienic_name; + let item = self.resolve_name_in_module(module, name, ns, true, record_used); + if let Success(binding) = item { + // The ident resolves to an item. + return Some(LexicalScopeBinding::Item(binding)); } + // We can only see through anonymous modules - if module.def.is_some() { return Failed(None); } + if module.def.is_some() { return None; } } } - Failed(None) + None + } + + fn resolve_item_in_lexical_scope(&mut self, + name: Name, + namespace: Namespace, + record_used: bool) + -> ResolveResult<&'a NameBinding<'a>> { + let ident = hir::Ident::from_name(name); + match self.resolve_ident_in_lexical_scope(ident, namespace, record_used) { + Some(LexicalScopeBinding::Item(binding)) => Success(binding), + _ => Failed(None), + } } /// Returns the nearest normal module parent of the given module. @@ -2861,33 +2892,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { namespace: Namespace, record_used: bool) -> Option<LocalDef> { - // Check the local set of ribs. - let name = match namespace { ValueNS => ident.name, TypeNS => ident.unhygienic_name }; - - for i in (0 .. self.get_ribs(namespace).len()).rev() { - if let Some(def) = self.get_ribs(namespace)[i].bindings.get(&name).cloned() { - return Some(LocalDef { - ribs: Some((namespace, i)), - def: def, - }); - } - - if let ModuleRibKind(module) = self.get_ribs(namespace)[i].kind { - if let Success(binding) = self.resolve_name_in_module(module, - ident.unhygienic_name, - namespace, - true, - record_used) { - if let Some(def) = binding.def() { - return Some(LocalDef::from_def(def)); - } - } - // We can only see through anonymous modules - if module.def.is_some() { return None; } - } - } - - None + Some(match self.resolve_ident_in_lexical_scope(ident, namespace, record_used) { + Some(LexicalScopeBinding::LocalDef(local_def)) => local_def, + Some(LexicalScopeBinding::Item(binding)) => LocalDef::from_def(binding.def().unwrap()), + None => return None, + }) } fn with_no_errors<T, F>(&mut self, f: F) -> T |
