From 8563a193847ff404f4f49f8dfdac2785cfb035bb Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 9 Mar 2021 19:37:21 -0800 Subject: [PATCH] Document `Res` and its friends --- compiler/rustc_hir/src/def.rs | 157 +++++++++++++++++++++++++++++++--- 1 file changed, 143 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index a81eb747a33..de10d88c1d2 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -20,6 +20,7 @@ pub enum CtorOf { Variant, } +/// What kind of constructor something is. #[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)] #[derive(HashStable_Generic)] pub enum CtorKind { @@ -31,6 +32,7 @@ pub enum CtorKind { Fictive, } +/// An attribute that is not a macro; e.g., `#[inline]` or `#[rustfmt::skip]`. #[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)] #[derive(HashStable_Generic)] pub enum NonMacroAttrKind { @@ -47,33 +49,51 @@ pub enum NonMacroAttrKind { Registered, } +/// What kind of definition something is; e.g., `mod` vs `struct`. #[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)] #[derive(HashStable_Generic)] pub enum DefKind { // Type namespace Mod, - /// Refers to the struct itself, `DefKind::Ctor` refers to its constructor if it exists. + /// Refers to the struct itself, [`DefKind::Ctor`] refers to its constructor if it exists. Struct, Union, Enum, - /// Refers to the variant itself, `DefKind::Ctor` refers to its constructor if it exists. + /// Refers to the variant itself, [`DefKind::Ctor`] refers to its constructor if it exists. Variant, Trait, - /// `type Foo = Bar;` + /// Type alias: `type Foo = Bar;` TyAlias, + /// Type from an `extern` block. ForeignTy, + /// Trait alias: `trait IntIterator = Iterator;` TraitAlias, + /// Associated type: `trait MyTrait { type Assoc; }` AssocTy, + /// Type parameter: the `T` in `struct Vec { ... }` TyParam, // Value namespace Fn, Const, + /// Constant generic parameter: `struct Foo { ... }` ConstParam, Static, /// Refers to the struct or enum variant's constructor. + /// + /// The reason `Ctor` exists in addition to [`DefKind::Struct`] and + /// [`DefKind::Variant`] is because structs and enum variants exist + /// in the *type* namespace, whereas struct and enum variant *constructors* + /// exist in the *value* namespace. + /// + /// You may wonder why enum variants exist in the type namespace as opposed + /// to the value namespace. Check out [RFC 2593] for intuition on why that is. + /// + /// [RFC 2593]: https://github.com/rust-lang/rfcs/pull/2593 Ctor(CtorOf, CtorKind), + /// Associated function: `impl MyStruct { fn associated() {} }` AssocFn, + /// Associated constant: `trait MyTrait { const ASSOC: usize; }` AssocConst, // Macro namespace @@ -82,11 +102,16 @@ pub enum DefKind { // Not namespaced (or they are, but we don't treat them so) ExternCrate, Use, + /// An `extern` block. ForeignMod, + /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`, or `const { 1 + 2}` AnonConst, + /// Opaque type, aka `impl Trait`. OpaqueTy, Field, + /// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }` LifetimeParam, + /// A use of [`global_asm!`]. GlobalAsm, Impl, Closure, @@ -196,35 +221,130 @@ impl DefKind { } /// The resolution of a path or export. +/// +/// For every path or identifier in Rust, the compiler must determine +/// what the path refers to. This process is called name resolution, +/// and `Res` is the primary result of name resolution. +/// +/// For example, everything prefixed with `/* Res */` in this example has +/// an associated `Res`: +/// +/// ``` +/// fn str_to_string(s: & /* Res */ str) -> /* Res */ String { +/// /* Res */ String::from(/* Res */ s) +/// } +/// +/// /* Res */ str_to_string("hello"); +/// ``` +/// +/// The associated `Res`s will be: +/// +/// - `str` will resolve to [`Res::PrimTy`]; +/// - `String` will resolve to [`Res::Def`], and the `Res` will include the [`DefId`] +/// for `String` as defined in the standard library; +/// - `String::from` will also resolve to [`Res::Def`], with the [`DefId`] +/// pointing to `String::from`; +/// - `s` will resolve to [`Res::Local`]; +/// - the call to `str_to_string` will resolve to [`Res::Def`], with the [`DefId`] +/// pointing to the definition of `str_to_string` in the current crate. +// #[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)] #[derive(HashStable_Generic)] pub enum Res { + /// Definition having a unique ID (`DefId`), corresponds to something defined in user code. + /// + /// **Not bound to a specific namespace.** Def(DefKind, DefId), // Type namespace - PrimTy(hir::PrimTy), - /// `Self`, with both an optional trait and impl `DefId`. + /// A primitive type such as `i32` or `str`. /// - /// HACK(min_const_generics): impl self types also have an optional requirement to not mention + /// **Belongs to the type namespace.** + PrimTy(hir::PrimTy), + /// The `Self` type, optionally with the trait it is associated with + /// and optionally with the [`DefId`] of the impl it is associated with. + /// + /// **Belongs to the type namespace.** + /// + /// For example, the `Self` in + /// + /// ``` + /// trait Foo { + /// fn foo() -> Box; + /// } + /// ``` + /// + /// would have the [`DefId`] of `Foo` associated with it. The `Self` in + /// + /// ``` + /// struct Bar; + /// + /// impl Bar { + /// fn new() -> Self { Bar } + /// } + /// ``` + /// + /// would have the [`DefId`] of the impl associated with it. Finally, the `Self` in + /// + /// ``` + /// impl Foo for Bar { + /// fn foo() -> Box { Box::new(Bar) } + /// } + /// ``` + /// + /// would have both the [`DefId`] of `Foo` and the [`DefId`] of the impl + /// associated with it. + /// + /// *See also [`Res::SelfCtor`].* + /// + /// ----- + /// + /// HACK(min_const_generics): impl self types also have an optional requirement to **not** mention /// any generic parameters to allow the following with `min_const_generics`: - /// ```rust - /// impl Foo { fn test() -> [u8; std::mem::size_of::()] {} } + /// ``` + /// impl Foo { fn test() -> [u8; std::mem::size_of::()] { todo!() } } /// ``` /// We do however allow `Self` in repeat expression even if it is generic to not break code /// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint. /// /// FIXME(lazy_normalization_consts): Remove this bodge once that feature is stable. - SelfTy(Option /* trait */, Option<(DefId, bool)> /* impl */), - ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]` + SelfTy( + /// Optionally, the trait associated with this `Self` type. + Option, + /// Optionally, the impl associated with this `Self` type. + Option<(DefId, bool)>, + ), + /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`. + /// + /// **Belongs to the type namespace.** + ToolMod, // Value namespace - SelfCtor(DefId /* impl */), // `DefId` refers to the impl + /// The `Self` constructor, along with the [`DefId`] + /// of the impl it is associated with. + /// + /// **Belongs to the value namespace.** + /// + /// *See also [`Res::SelfTy`].* + SelfCtor(DefId), + /// A local variable or function parameter. + /// + /// **Belongs to the value namespace.** Local(Id), // Macro namespace + /// An attribute that is *not* implemented via macro. + /// E.g., `#[inline]` and `#[rustfmt::skip]`, which are essentially directives, + /// as opposed to `#[test]`, which is a builtin macro. + /// + /// **Belongs to the macro namespace.** NonMacroAttr(NonMacroAttrKind), // e.g., `#[inline]` or `#[rustfmt::skip]` // All namespaces + /// Name resolution failed. We use a dummy `Res` variant so later phases + /// of the compiler won't crash and can instead report more errors. + /// + /// **Not bound to a specific namespace.** Err, } @@ -275,17 +395,26 @@ impl PartialRes { } } -/// Different kinds of symbols don't influence each other. -/// -/// Therefore, they have a separate universe (namespace). +/// Different kinds of symbols can coexist even if they share the same textual name. +/// Therefore, they each have a separate universe (known as a "namespace"). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum Namespace { + /// The type namespace includes `struct`s, `enum`s, `union`s, `trait`s, and `mod`s + /// (and, by extension, crates). + /// + /// Note that the type namespace includes other items; this is not an + /// exhaustive list. TypeNS, + /// The value namespace includes `fn`s, `const`s, `static`s, and local variables (including function arguments). ValueNS, + /// The macro namespace includes `macro_rules!` macros, declarative `macro`s, + /// procedural macros, attribute macros, `derive` macros, and non-macro attributes + /// like `#[inline]` and `#[rustfmt::skip]`. MacroNS, } impl Namespace { + /// The English description of the namespace. pub fn descr(self) -> &'static str { match self { Self::TypeNS => "type",