use crate::hir; use rustc_ast as ast; use rustc_ast::NodeId; use rustc_macros::HashStable_Generic; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::hygiene::MacroKind; use rustc_span::Symbol; use std::array::IntoIter; use std::fmt::Debug; /// Encodes if a `DefKind::Ctor` is the constructor of an enum variant or a struct. #[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)] #[derive(HashStable_Generic)] pub enum CtorOf { /// This `DefKind::Ctor` is a synthesized constructor of a tuple or unit struct. Struct, /// This `DefKind::Ctor` is a synthesized constructor of a tuple or unit variant. Variant, } /// What kind of constructor something is. #[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)] #[derive(HashStable_Generic)] pub enum CtorKind { /// Constructor function automatically created by a tuple struct/variant. Fn, /// Constructor constant automatically created by a unit struct/variant. Const, } /// 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 { /// Single-segment attribute defined by the language (`#[inline]`) Builtin(Symbol), /// Multi-segment custom attribute living in a "tool module" (`#[rustfmt::skip]`). Tool, /// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`). DeriveHelper, /// Single-segment custom attribute registered by a derive macro /// but used before that derive macro was expanded (deprecated). DeriveHelperCompat, } /// 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. Struct, Union, Enum, /// Refers to the variant itself, [`DefKind::Ctor`] refers to its constructor if it exists. Variant, Trait, /// 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(ast::Mutability), /// 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() {} }` /// or `trait Foo { fn associated() {} }` AssocFn, /// Associated constant: `trait MyTrait { const ASSOC: usize; }` AssocConst, // Macro namespace Macro(MacroKind), // 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]` AnonConst, /// An inline constant, e.g. `const { 1 + 2 }` InlineConst, /// Opaque type, aka `impl Trait`. OpaqueTy, /// A return-position `impl Trait` in a trait definition ImplTraitPlaceholder, Field, /// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }` LifetimeParam, /// A use of `global_asm!`. GlobalAsm, Impl, Closure, Generator, } impl DefKind { pub fn descr(self, def_id: DefId) -> &'static str { match self { DefKind::Fn => "function", DefKind::Mod if def_id.is_crate_root() && !def_id.is_local() => "crate", DefKind::Mod => "module", DefKind::Static(..) => "static", DefKind::Enum => "enum", DefKind::Variant => "variant", DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) => "tuple variant", DefKind::Ctor(CtorOf::Variant, CtorKind::Const) => "unit variant", DefKind::Struct => "struct", DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) => "tuple struct", DefKind::Ctor(CtorOf::Struct, CtorKind::Const) => "unit struct", DefKind::OpaqueTy => "opaque type", DefKind::ImplTraitPlaceholder => "opaque type in trait", DefKind::TyAlias => "type alias", DefKind::TraitAlias => "trait alias", DefKind::AssocTy => "associated type", DefKind::Union => "union", DefKind::Trait => "trait", DefKind::ForeignTy => "foreign type", DefKind::AssocFn => "associated function", DefKind::Const => "constant", DefKind::AssocConst => "associated constant", DefKind::TyParam => "type parameter", DefKind::ConstParam => "const parameter", DefKind::Macro(macro_kind) => macro_kind.descr(), DefKind::LifetimeParam => "lifetime parameter", DefKind::Use => "import", DefKind::ForeignMod => "foreign module", DefKind::AnonConst => "constant expression", DefKind::InlineConst => "inline constant", DefKind::Field => "field", DefKind::Impl => "implementation", DefKind::Closure => "closure", DefKind::Generator => "generator", DefKind::ExternCrate => "extern crate", DefKind::GlobalAsm => "global assembly block", } } /// Gets an English article for the definition. pub fn article(&self) -> &'static str { match *self { DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocFn | DefKind::Enum | DefKind::OpaqueTy | DefKind::Impl | DefKind::Use | DefKind::InlineConst | DefKind::ExternCrate => "an", DefKind::Macro(macro_kind) => macro_kind.article(), _ => "a", } } pub fn ns(&self) -> Option { match self { DefKind::Mod | DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Variant | DefKind::Trait | DefKind::OpaqueTy | DefKind::TyAlias | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy | DefKind::TyParam => Some(Namespace::TypeNS), DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static(..) | DefKind::Ctor(..) | DefKind::AssocFn | DefKind::AssocConst => Some(Namespace::ValueNS), DefKind::Macro(..) => Some(Namespace::MacroNS), // Not namespaced. DefKind::AnonConst | DefKind::InlineConst | DefKind::Field | DefKind::LifetimeParam | DefKind::ExternCrate | DefKind::Closure | DefKind::Generator | DefKind::Use | DefKind::ForeignMod | DefKind::GlobalAsm | DefKind::Impl | DefKind::ImplTraitPlaceholder => None, } } #[inline] pub fn is_fn_like(self) -> bool { match self { DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator => true, _ => false, } } /// Whether `query get_codegen_attrs` should be used with this definition. pub fn has_codegen_attrs(self) -> bool { match self { DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Closure | DefKind::Generator | DefKind::Static(_) => true, DefKind::Mod | DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Variant | DefKind::Trait | DefKind::TyAlias | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy | DefKind::Const | DefKind::AssocConst | DefKind::Macro(..) | DefKind::Use | DefKind::ForeignMod | DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder | DefKind::Impl | DefKind::Field | DefKind::TyParam | DefKind::ConstParam | DefKind::LifetimeParam | DefKind::AnonConst | DefKind::InlineConst | DefKind::GlobalAsm | DefKind::ExternCrate => false, } } } /// 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 /// A primitive type such as `i32` or `str`. /// /// **Belongs to the type namespace.** PrimTy(hir::PrimTy), /// The `Self` type, as used within a trait. /// /// **Belongs to the type namespace.** /// /// See the examples on [`Res::SelfTyAlias`] for details. SelfTyParam { /// The trait this `Self` is a generic parameter for. trait_: DefId, }, /// The `Self` type, as used somewhere other than within a trait. /// /// **Belongs to the type namespace.** /// /// Examples: /// ``` /// struct Bar(Box); // SelfTyAlias /// /// trait Foo { /// fn foo() -> Box; // SelfTyParam /// } /// /// impl Bar { /// fn blah() { /// let _: Self; // SelfTyAlias /// } /// } /// /// impl Foo for Bar { /// fn foo() -> Box { // SelfTyAlias /// let _: Self; // SelfTyAlias /// /// todo!() /// } /// } /// ``` /// *See also [`Res::SelfCtor`].* /// SelfTyAlias { /// The item introducing the `Self` type alias. Can be used in the `type_of` query /// to get the underlying type. alias_to: DefId, /// Whether the `Self` type is disallowed from mentioning generics (i.e. when used in an /// anonymous constant). /// /// HACK(min_const_generics): self types also have an optional requirement to **not** /// mention any generic parameters to allow the following with `min_const_generics`: /// ``` /// # struct Foo; /// impl Foo { fn test() -> [u8; std::mem::size_of::()] { todo!() } } /// /// struct Bar([u8; baz::()]); /// const fn baz() -> usize { 10 } /// ``` /// 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: /// ``` /// fn foo() { /// let _bar = [1_u8; std::mem::size_of::<*mut T>()]; /// } /// ``` // FIXME(generic_const_exprs): Remove this bodge once that feature is stable. forbid_generic: bool, /// Is this within an `impl Foo for bar`? is_trait_impl: bool, }, // Value namespace /// The `Self` constructor, along with the [`DefId`] /// of the impl it is associated with. /// /// **Belongs to the value namespace.** /// /// *See also [`Res::SelfTyParam`] and [`Res::SelfTyAlias`].* SelfCtor(DefId), /// A local variable or function parameter. /// /// **Belongs to the value namespace.** Local(Id), /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`. /// /// **Belongs to the type namespace.** ToolMod, // 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, } /// The result of resolving a path before lowering to HIR, /// with "module" segments resolved and associated item /// segments deferred to type checking. /// `base_res` is the resolution of the resolved part of the /// path, `unresolved_segments` is the number of unresolved /// segments. /// /// ```text /// module::Type::AssocX::AssocY::MethodOrAssocType /// ^~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// base_res unresolved_segments = 3 /// /// ::AssocX::AssocY::MethodOrAssocType /// ^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~ /// base_res unresolved_segments = 2 /// ``` #[derive(Copy, Clone, Debug)] pub struct PartialRes { base_res: Res, unresolved_segments: usize, } impl PartialRes { #[inline] pub fn new(base_res: Res) -> Self { PartialRes { base_res, unresolved_segments: 0 } } #[inline] pub fn with_unresolved_segments(base_res: Res, mut unresolved_segments: usize) -> Self { if base_res == Res::Err { unresolved_segments = 0 } PartialRes { base_res, unresolved_segments } } #[inline] pub fn base_res(&self) -> Res { self.base_res } #[inline] pub fn unresolved_segments(&self) -> usize { self.unresolved_segments } #[inline] pub fn full_res(&self) -> Option> { (self.unresolved_segments == 0).then_some(self.base_res) } #[inline] pub fn expect_full_res(&self) -> Res { self.full_res().expect("unexpected unresolved segments") } } /// 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, 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", Self::ValueNS => "value", Self::MacroNS => "macro", } } } /// Just a helper ‒ separate structure for each namespace. #[derive(Copy, Clone, Default, Debug)] pub struct PerNS { pub value_ns: T, pub type_ns: T, pub macro_ns: T, } impl PerNS { pub fn map U>(self, mut f: F) -> PerNS { PerNS { value_ns: f(self.value_ns), type_ns: f(self.type_ns), macro_ns: f(self.macro_ns) } } pub fn into_iter(self) -> IntoIter { [self.value_ns, self.type_ns, self.macro_ns].into_iter() } pub fn iter(&self) -> IntoIter<&T, 3> { [&self.value_ns, &self.type_ns, &self.macro_ns].into_iter() } } impl ::std::ops::Index for PerNS { type Output = T; fn index(&self, ns: Namespace) -> &T { match ns { Namespace::ValueNS => &self.value_ns, Namespace::TypeNS => &self.type_ns, Namespace::MacroNS => &self.macro_ns, } } } impl ::std::ops::IndexMut for PerNS { fn index_mut(&mut self, ns: Namespace) -> &mut T { match ns { Namespace::ValueNS => &mut self.value_ns, Namespace::TypeNS => &mut self.type_ns, Namespace::MacroNS => &mut self.macro_ns, } } } impl PerNS> { /// Returns `true` if all the items in this collection are `None`. pub fn is_empty(&self) -> bool { self.type_ns.is_none() && self.value_ns.is_none() && self.macro_ns.is_none() } /// Returns an iterator over the items which are `Some`. pub fn present_items(self) -> impl Iterator { [self.type_ns, self.value_ns, self.macro_ns].into_iter().flatten() } } impl CtorKind { pub fn from_ast(vdata: &ast::VariantData) -> Option<(CtorKind, NodeId)> { match *vdata { ast::VariantData::Tuple(_, node_id) => Some((CtorKind::Fn, node_id)), ast::VariantData::Unit(node_id) => Some((CtorKind::Const, node_id)), ast::VariantData::Struct(..) => None, } } } impl NonMacroAttrKind { pub fn descr(self) -> &'static str { match self { NonMacroAttrKind::Builtin(..) => "built-in attribute", NonMacroAttrKind::Tool => "tool attribute", NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::DeriveHelperCompat => { "derive helper attribute" } } } pub fn article(self) -> &'static str { "a" } /// Users of some attributes cannot mark them as used, so they are considered always used. pub fn is_used(self) -> bool { match self { NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::DeriveHelperCompat => true, NonMacroAttrKind::Builtin(..) => false, } } } impl Res { /// Return the `DefId` of this `Def` if it has an ID, else panic. pub fn def_id(&self) -> DefId where Id: Debug, { self.opt_def_id().unwrap_or_else(|| panic!("attempted .def_id() on invalid res: {self:?}")) } /// Return `Some(..)` with the `DefId` of this `Res` if it has a ID, else `None`. pub fn opt_def_id(&self) -> Option { match *self { Res::Def(_, id) => Some(id), Res::Local(..) | Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::SelfCtor(..) | Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => None, } } /// Return the `DefId` of this `Res` if it represents a module. pub fn mod_def_id(&self) -> Option { match *self { Res::Def(DefKind::Mod, id) => Some(id), _ => None, } } /// A human readable name for the res kind ("function", "module", etc.). pub fn descr(&self) -> &'static str { match *self { Res::Def(kind, def_id) => kind.descr(def_id), Res::SelfCtor(..) => "self constructor", Res::PrimTy(..) => "builtin type", Res::Local(..) => "local variable", Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => "self type", Res::ToolMod => "tool module", Res::NonMacroAttr(attr_kind) => attr_kind.descr(), Res::Err => "unresolved item", } } /// Gets an English article for the `Res`. pub fn article(&self) -> &'static str { match *self { Res::Def(kind, _) => kind.article(), Res::NonMacroAttr(kind) => kind.article(), Res::Err => "an", _ => "a", } } pub fn map_id(self, mut map: impl FnMut(Id) -> R) -> Res { match self { Res::Def(kind, id) => Res::Def(kind, id), Res::SelfCtor(id) => Res::SelfCtor(id), Res::PrimTy(id) => Res::PrimTy(id), Res::Local(id) => Res::Local(map(id)), Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ }, Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } => { Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } } Res::ToolMod => Res::ToolMod, Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind), Res::Err => Res::Err, } } pub fn apply_id(self, mut map: impl FnMut(Id) -> Result) -> Result, E> { Ok(match self { Res::Def(kind, id) => Res::Def(kind, id), Res::SelfCtor(id) => Res::SelfCtor(id), Res::PrimTy(id) => Res::PrimTy(id), Res::Local(id) => Res::Local(map(id)?), Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ }, Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } => { Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } } Res::ToolMod => Res::ToolMod, Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind), Res::Err => Res::Err, }) } #[track_caller] pub fn expect_non_local(self) -> Res { self.map_id( #[track_caller] |_| panic!("unexpected `Res::Local`"), ) } pub fn macro_kind(self) -> Option { match self { Res::Def(DefKind::Macro(kind), _) => Some(kind), Res::NonMacroAttr(..) => Some(MacroKind::Attr), _ => None, } } /// Returns `None` if this is `Res::Err` pub fn ns(&self) -> Option { match self { Res::Def(kind, ..) => kind.ns(), Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::ToolMod => { Some(Namespace::TypeNS) } Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS), Res::NonMacroAttr(..) => Some(Namespace::MacroNS), Res::Err => None, } } /// Always returns `true` if `self` is `Res::Err` pub fn matches_ns(&self, ns: Namespace) -> bool { self.ns().map_or(true, |actual_ns| actual_ns == ns) } /// Returns whether such a resolved path can occur in a tuple struct/variant pattern pub fn expected_in_tuple_struct_pat(&self) -> bool { matches!(self, Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..)) } /// Returns whether such a resolved path can occur in a unit struct/variant pattern pub fn expected_in_unit_struct_pat(&self) -> bool { matches!(self, Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::SelfCtor(..)) } } /// Resolution for a lifetime appearing in a type. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum LifetimeRes { /// Successfully linked the lifetime to a generic parameter. Param { /// Id of the generic parameter that introduced it. param: LocalDefId, /// Id of the introducing place. That can be: /// - an item's id, for the item's generic parameters; /// - a TraitRef's ref_id, identifying the `for<...>` binder; /// - a BareFn type's id. /// /// This information is used for impl-trait lifetime captures, to know when to or not to /// capture any given lifetime. binder: NodeId, }, /// Created a generic parameter for an anonymous lifetime. Fresh { /// Id of the generic parameter that introduced it. /// /// Creating the associated `LocalDefId` is the responsibility of lowering. param: NodeId, /// Id of the introducing place. See `Param`. binder: NodeId, }, /// This variant is used for anonymous lifetimes that we did not resolve during /// late resolution. Those lifetimes will be inferred by typechecking. Infer, /// Explicit `'static` lifetime. Static, /// Resolution failure. Error, /// HACK: This is used to recover the NodeId of an elided lifetime. ElidedAnchor { start: NodeId, end: NodeId }, }