diff options
| author | Tim Neumann <mail@timnn.me> | 2018-03-26 15:14:50 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-03-26 15:14:50 +0200 |
| commit | 3d7a04610de0ac95e85eb13f814b45a26458dcae (patch) | |
| tree | eac279fe5de2ef418d6dff1d629b0d996d83fc9f | |
| parent | 5e4603f99066eaf2c1cf19ac3afbac9057b1e177 (diff) | |
| parent | 433a03e6ff914bd367f129457a3d80822c9c6a42 (diff) | |
| download | rust-3d7a04610de0ac95e85eb13f814b45a26458dcae.tar.gz rust-3d7a04610de0ac95e85eb13f814b45a26458dcae.zip | |
Rollup merge of #48693 - vorner:doc-name-resolution, r=petrochenkov
Some comments and documentation for name resolution crate Hello I'm trying to get a grasp of how the name resolution crate works, as part of helping with https://github.com/rust-lang-nursery/rustc-guide/issues/16. Not that I'd be succeeding much, but as I was reading the code, I started to put some notes into it, to help me understand. I guess I didn't get very far yet, but I'd like to share what I have, in case it might be useful for someone else. I hope these are correct (even if incomplete), but I'll be glad for a fast check in case I put something misleading there.
| -rw-r--r-- | src/librustc_resolve/lib.rs | 61 |
1 files changed, 58 insertions, 3 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2cb2c76c632..4d11960c320 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -162,6 +162,10 @@ enum ResolutionError<'a> { ForwardDeclaredTyParam, } +/// Combines an error with provided span and emits it +/// +/// This takes the error provided, combines it with the span and any additional spans inside the +/// error and emits it. fn resolve_error<'sess, 'a>(resolver: &'sess Resolver, span: Span, resolution_error: ResolutionError<'a>) { @@ -486,7 +490,7 @@ struct BindingInfo { binding_mode: BindingMode, } -// Map from the name in a pattern to its binding mode. +/// Map from the name in a pattern to its binding mode. type BindingMap = FxHashMap<Ident, BindingInfo>; #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -681,6 +685,9 @@ impl<'a> PathSource<'a> { } } +/// Different kinds of symbols don't influence each other. +/// +/// Therefore, they have a separate universe (namespace). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum Namespace { TypeNS, @@ -688,6 +695,7 @@ pub enum Namespace { MacroNS, } +/// Just a helper ‒ separate structure for each namespace. #[derive(Clone, Default, Debug)] pub struct PerNS<T> { value_ns: T, @@ -784,6 +792,7 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder { } } +/// This thing walks the whole crate in DFS manner, visiting each item, resolving names as it goes. impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { fn visit_item(&mut self, item: &'tcx Item) { self.resolve_item(item); @@ -910,7 +919,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { fn visit_generics(&mut self, generics: &'tcx Generics) { // For type parameter defaults, we have to ban access // to following type parameters, as the Substs can only - // provide previous type parameters as they're built. + // provide previous type parameters as they're built. We + // put all the parameters on the ban list and then remove + // them one by one as they are processed and become available. let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind); default_ban_rib.bindings.extend(generics.params.iter() .filter_map(|p| if let GenericParam::Type(ref tp) = *p { Some(tp) } else { None }) @@ -986,6 +997,17 @@ enum RibKind<'a> { } /// One local scope. +/// +/// A rib represents a scope names can live in. Note that these appear in many places, not just +/// around braces. At any place where the list of accessible names (of the given namespace) +/// changes or a new restrictions on the name accessibility are introduced, a new rib is put onto a +/// stack. This may be, for example, a `let` statement (because it introduces variables), a macro, +/// etc. +/// +/// Different [rib kinds](enum.RibKind) are transparent for different names. +/// +/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When +/// resolving, the name is looked up from inside out. #[derive(Debug)] struct Rib<'a> { bindings: FxHashMap<Ident, Def>, @@ -1001,6 +1023,11 @@ impl<'a> Rib<'a> { } } +/// An intermediate resolution result. +/// +/// This refers to the thing referred by a name. The difference between `Def` and `Item` is that +/// items are visible in their whole block, while defs only from the place they are defined +/// forward. enum LexicalScopeBinding<'a> { Item(&'a NameBinding<'a>), Def(Def), @@ -1031,7 +1058,26 @@ enum PathResult<'a> { } enum ModuleKind { + /// An anonymous module, eg. just a block. + /// + /// ``` + /// fn main() { + /// fn f() {} // (1) + /// { // This is an anonymous module + /// f(); // This resolves to (2) as we are inside the block. + /// fn f() {} // (2) + /// } + /// f(); // Resolves to (1) + /// } + /// ``` Block(NodeId), + /// Any module with a name. + /// + /// This could be: + /// + /// * A normal module ‒ either `mod from_file;` or `mod from_block { }`. + /// * A trait or an enum (it implicitly contains associated types, methods and variant + /// constructors). Def(Def, Name), } @@ -1316,6 +1362,9 @@ impl<'a> NameBinding<'a> { } /// Interns the names of the primitive types. +/// +/// All other types are defined somewhere and possibly imported, but the primitive ones need +/// special handling, since they have no place of origin. struct PrimitiveTypeTable { primitive_types: FxHashMap<Name, PrimTy>, } @@ -1350,6 +1399,8 @@ impl PrimitiveTypeTable { } /// The main resolver class. +/// +/// This is the visitor that walks the whole crate. pub struct Resolver<'a> { session: &'a Session, cstore: &'a CrateStore, @@ -1481,6 +1532,7 @@ pub struct Resolver<'a> { injected_crate: Option<Module<'a>>, } +/// Nothing really interesting here, it just provides memory for the rest of the crate. pub struct ResolverArenas<'a> { modules: arena::TypedArena<ModuleData<'a>>, local_modules: RefCell<Vec<Module<'a>>>, @@ -1526,10 +1578,12 @@ impl<'a, 'b: 'a> ty::DefIdTree for &'a Resolver<'b> { match id.krate { LOCAL_CRATE => self.definitions.def_key(id.index).parent, _ => self.cstore.def_key(id).parent, - }.map(|index| DefId { index: index, ..id }) + }.map(|index| DefId { index, ..id }) } } +/// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that +/// the resolver is no longer needed as all the relevant information is inline. impl<'a> hir::lowering::Resolver for Resolver<'a> { fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) { self.resolve_hir_path_cb(path, is_value, @@ -1752,6 +1806,7 @@ impl<'a> Resolver<'a> { } } + /// Runs the function on each namespace. fn per_ns<T, F: FnMut(&mut Self, Namespace) -> T>(&mut self, mut f: F) -> PerNS<T> { PerNS { type_ns: f(self, TypeNS), |
