1
Fork 0

mv compiler to compiler/

This commit is contained in:
mark 2020-08-27 22:58:48 -05:00 committed by Vadim Petrochenkov
parent db534b3ac2
commit 9e5f7d5631
1686 changed files with 941 additions and 1051 deletions

View file

@ -0,0 +1,52 @@
/// This declares a list of types which can be allocated by `Arena`.
///
/// The `few` modifier will cause allocation to use the shared arena and recording the destructor.
/// This is faster and more memory efficient if there's only a few allocations of the type.
/// Leaving `few` out will cause the type to get its own dedicated `TypedArena` which is
/// faster and more memory efficient if there is lots of allocations.
///
/// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]`,
/// where `T` is the type listed. These impls will appear in the implement_ty_decoder! macro.
#[macro_export]
macro_rules! arena_types {
($macro:path, $args:tt, $tcx:lifetime) => (
$macro!($args, [
// HIR types
[few] hir_krate: rustc_hir::Crate<$tcx>,
[] arm: rustc_hir::Arm<$tcx>,
[] asm_operand: rustc_hir::InlineAsmOperand<$tcx>,
[] asm_template: rustc_ast::InlineAsmTemplatePiece,
[] attribute: rustc_ast::Attribute,
[] block: rustc_hir::Block<$tcx>,
[] bare_fn_ty: rustc_hir::BareFnTy<$tcx>,
[few] global_asm: rustc_hir::GlobalAsm,
[] generic_arg: rustc_hir::GenericArg<$tcx>,
[] generic_args: rustc_hir::GenericArgs<$tcx>,
[] generic_bound: rustc_hir::GenericBound<$tcx>,
[] generic_param: rustc_hir::GenericParam<$tcx>,
[] expr: rustc_hir::Expr<$tcx>,
[] field: rustc_hir::Field<$tcx>,
[] field_pat: rustc_hir::FieldPat<$tcx>,
[] fn_decl: rustc_hir::FnDecl<$tcx>,
[] foreign_item: rustc_hir::ForeignItem<$tcx>,
[] impl_item_ref: rustc_hir::ImplItemRef<$tcx>,
[few] inline_asm: rustc_hir::InlineAsm<$tcx>,
[few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>,
[] local: rustc_hir::Local<$tcx>,
[few] macro_def: rustc_hir::MacroDef<$tcx>,
[] param: rustc_hir::Param<$tcx>,
[] pat: rustc_hir::Pat<$tcx>,
[] path: rustc_hir::Path<$tcx>,
[] path_segment: rustc_hir::PathSegment<$tcx>,
[] poly_trait_ref: rustc_hir::PolyTraitRef<$tcx>,
[] qpath: rustc_hir::QPath<$tcx>,
[] stmt: rustc_hir::Stmt<$tcx>,
[] struct_field: rustc_hir::StructField<$tcx>,
[] trait_item_ref: rustc_hir::TraitItemRef,
[] ty: rustc_hir::Ty<$tcx>,
[] type_binding: rustc_hir::TypeBinding<$tcx>,
[] variant: rustc_hir::Variant<$tcx>,
[] where_predicate: rustc_hir::WherePredicate<$tcx>,
], $tcx);
)
}

View file

@ -0,0 +1,469 @@
use crate::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use crate::hir;
use rustc_ast as ast;
use rustc_ast::NodeId;
use rustc_macros::HashStable_Generic;
use rustc_span::hygiene::MacroKind;
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,
}
#[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,
/// Unusable name in value namespace created by a struct variant.
Fictive,
}
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
#[derive(HashStable_Generic)]
pub enum NonMacroAttrKind {
/// Single-segment attribute defined by the language (`#[inline]`)
Builtin,
/// 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 with `#[register_attr]`.
Registered,
}
#[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 Foo = Bar;`
TyAlias,
ForeignTy,
TraitAlias,
AssocTy,
TyParam,
// Value namespace
Fn,
Const,
ConstParam,
Static,
/// Refers to the struct or enum variant's constructor.
Ctor(CtorOf, CtorKind),
AssocFn,
AssocConst,
// Macro namespace
Macro(MacroKind),
// Not namespaced (or they are, but we don't treat them so)
ExternCrate,
Use,
ForeignMod,
AnonConst,
OpaqueTy,
Field,
LifetimeParam,
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.index == CRATE_DEF_INDEX && def_id.krate != LOCAL_CRATE => {
"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::Ctor(CtorOf::Variant, CtorKind::Fictive) => "struct variant",
DefKind::Struct => "struct",
DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) => "tuple struct",
DefKind::Ctor(CtorOf::Struct, CtorKind::Const) => "unit struct",
DefKind::Ctor(CtorOf::Struct, CtorKind::Fictive) => {
panic!("impossible struct constructor")
}
DefKind::OpaqueTy => "opaque type",
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::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::ExternCrate => "an",
DefKind::Macro(macro_kind) => macro_kind.article(),
_ => "a",
}
}
pub fn ns(&self) -> Option<Namespace> {
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::Field
| DefKind::LifetimeParam
| DefKind::ExternCrate
| DefKind::Closure
| DefKind::Generator
| DefKind::Use
| DefKind::ForeignMod
| DefKind::GlobalAsm
| DefKind::Impl => None,
}
}
}
/// The resolution of a path or export.
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
#[derive(HashStable_Generic)]
pub enum Res<Id = hir::HirId> {
Def(DefKind, DefId),
// Type namespace
PrimTy(hir::PrimTy),
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`
// Value namespace
SelfCtor(DefId /* impl */), // `DefId` refers to the impl
Local(Id),
// Macro namespace
NonMacroAttr(NonMacroAttrKind), // e.g., `#[inline]` or `#[rustfmt::skip]`
// All namespaces
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
///
/// <T as Trait>::AssocX::AssocY::MethodOrAssocType
/// ^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~
/// base_res unresolved_segments = 2
/// ```
#[derive(Copy, Clone, Debug)]
pub struct PartialRes {
base_res: Res<NodeId>,
unresolved_segments: usize,
}
impl PartialRes {
#[inline]
pub fn new(base_res: Res<NodeId>) -> Self {
PartialRes { base_res, unresolved_segments: 0 }
}
#[inline]
pub fn with_unresolved_segments(base_res: Res<NodeId>, 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<NodeId> {
self.base_res
}
#[inline]
pub fn unresolved_segments(&self) -> usize {
self.unresolved_segments
}
}
/// 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,
ValueNS,
MacroNS,
}
impl 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<T> {
pub value_ns: T,
pub type_ns: T,
pub macro_ns: T,
}
impl<T> PerNS<T> {
pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> PerNS<U> {
PerNS { value_ns: f(self.value_ns), type_ns: f(self.type_ns), macro_ns: f(self.macro_ns) }
}
}
impl<T> ::std::ops::Index<Namespace> for PerNS<T> {
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<T> ::std::ops::IndexMut<Namespace> for PerNS<T> {
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<T> PerNS<Option<T>> {
/// 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<Item = T> {
use std::iter::once;
once(self.type_ns).chain(once(self.value_ns)).chain(once(self.macro_ns)).filter_map(|it| it)
}
}
impl CtorKind {
pub fn from_ast(vdata: &ast::VariantData) -> CtorKind {
match *vdata {
ast::VariantData::Tuple(..) => CtorKind::Fn,
ast::VariantData::Unit(..) => CtorKind::Const,
ast::VariantData::Struct(..) => CtorKind::Fictive,
}
}
pub fn from_hir(vdata: &hir::VariantData<'_>) -> CtorKind {
match *vdata {
hir::VariantData::Tuple(..) => CtorKind::Fn,
hir::VariantData::Unit(..) => CtorKind::Const,
hir::VariantData::Struct(..) => CtorKind::Fictive,
}
}
}
impl NonMacroAttrKind {
pub fn descr(self) -> &'static str {
match self {
NonMacroAttrKind::Builtin => "built-in attribute",
NonMacroAttrKind::Tool => "tool attribute",
NonMacroAttrKind::DeriveHelper => "derive helper attribute",
NonMacroAttrKind::Registered => "explicitly registered attribute",
}
}
pub fn article(self) -> &'static str {
match self {
NonMacroAttrKind::Registered => "an",
_ => "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 => true,
NonMacroAttrKind::Builtin | NonMacroAttrKind::Registered => false,
}
}
}
impl<Id> Res<Id> {
/// 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<DefId> {
match *self {
Res::Def(_, id) => Some(id),
Res::Local(..)
| Res::PrimTy(..)
| Res::SelfTy(..)
| 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<DefId> {
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::SelfTy(..) => "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<R>(self, mut map: impl FnMut(Id) -> R) -> Res<R> {
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::SelfTy(a, b) => Res::SelfTy(a, b),
Res::ToolMod => Res::ToolMod,
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
Res::Err => Res::Err,
}
}
pub fn macro_kind(self) -> Option<MacroKind> {
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<Namespace> {
match self {
Res::Def(kind, ..) => kind.ns(),
Res::PrimTy(..) | Res::SelfTy(..) | 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)
}
}

View file

@ -0,0 +1,457 @@
//! For each definition, we track the following data. A definition
//! here is defined somewhat circularly as "something with a `DefId`",
//! but it generally corresponds to things like structs, enums, etc.
//! There are also some rather random cases (like const initializer
//! expressions) that are mostly just leftovers.
pub use crate::def_id::DefPathHash;
use crate::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use crate::hir;
use rustc_ast::crate_disambiguator::CrateDisambiguator;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_index::vec::IndexVec;
use rustc_span::hygiene::ExpnId;
use rustc_span::symbol::{sym, Symbol};
use std::fmt::Write;
use std::hash::Hash;
use tracing::debug;
/// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa.
/// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey`
/// stores the `DefIndex` of its parent.
/// There is one `DefPathTable` for each crate.
#[derive(Clone, Default)]
pub struct DefPathTable {
index_to_key: IndexVec<DefIndex, DefKey>,
def_path_hashes: IndexVec<DefIndex, DefPathHash>,
}
impl DefPathTable {
fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex {
let index = {
let index = DefIndex::from(self.index_to_key.len());
debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
self.index_to_key.push(key);
index
};
self.def_path_hashes.push(def_path_hash);
debug_assert!(self.def_path_hashes.len() == self.index_to_key.len());
index
}
#[inline(always)]
pub fn def_key(&self, index: DefIndex) -> DefKey {
self.index_to_key[index]
}
#[inline(always)]
pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
let hash = self.def_path_hashes[index];
debug!("def_path_hash({:?}) = {:?}", index, hash);
hash
}
pub fn num_def_ids(&self) -> usize {
self.index_to_key.len()
}
pub fn enumerated_keys_and_path_hashes(
&self,
) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + '_ {
self.index_to_key
.iter_enumerated()
.map(move |(index, key)| (index, key, &self.def_path_hashes[index]))
}
pub fn all_def_path_hashes_and_def_ids(
&self,
krate: CrateNum,
) -> impl Iterator<Item = (DefPathHash, DefId)> + '_ {
self.def_path_hashes
.iter_enumerated()
.map(move |(index, hash)| (*hash, DefId { krate, index }))
}
}
/// The definition table containing node definitions.
/// It holds the `DefPathTable` for `LocalDefId`s/`DefPath`s.
/// It also stores mappings to convert `LocalDefId`s to/from `HirId`s.
#[derive(Clone)]
pub struct Definitions {
table: DefPathTable,
// FIXME(eddyb) ideally all `LocalDefId`s would be HIR owners.
pub(super) def_id_to_hir_id: IndexVec<LocalDefId, Option<hir::HirId>>,
/// The reverse mapping of `def_id_to_hir_id`.
pub(super) hir_id_to_def_id: FxHashMap<hir::HirId, LocalDefId>,
/// If `ExpnId` is an ID of some macro expansion,
/// then `DefId` is the normal module (`mod`) in which the expanded macro was defined.
parent_modules_of_macro_defs: FxHashMap<ExpnId, DefId>,
/// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
}
/// A unique identifier that we can use to lookup a definition
/// precisely. It combines the index of the definition's parent (if
/// any) with a `DisambiguatedDefPathData`.
#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)]
pub struct DefKey {
/// The parent path.
pub parent: Option<DefIndex>,
/// The identifier of this node.
pub disambiguated_data: DisambiguatedDefPathData,
}
impl DefKey {
fn compute_stable_hash(&self, parent_hash: DefPathHash) -> DefPathHash {
let mut hasher = StableHasher::new();
// We hash a `0u8` here to disambiguate between regular `DefPath` hashes,
// and the special "root_parent" below.
0u8.hash(&mut hasher);
parent_hash.hash(&mut hasher);
let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data;
::std::mem::discriminant(data).hash(&mut hasher);
if let Some(name) = data.get_opt_name() {
// Get a stable hash by considering the symbol chars rather than
// the symbol index.
name.as_str().hash(&mut hasher);
}
disambiguator.hash(&mut hasher);
DefPathHash(hasher.finish())
}
fn root_parent_stable_hash(
crate_name: &str,
crate_disambiguator: CrateDisambiguator,
) -> DefPathHash {
let mut hasher = StableHasher::new();
// Disambiguate this from a regular `DefPath` hash; see `compute_stable_hash()` above.
1u8.hash(&mut hasher);
crate_name.hash(&mut hasher);
crate_disambiguator.hash(&mut hasher);
DefPathHash(hasher.finish())
}
}
/// A pair of `DefPathData` and an integer disambiguator. The integer is
/// normally `0`, but in the event that there are multiple defs with the
/// same `parent` and `data`, we use this field to disambiguate
/// between them. This introduces some artificial ordering dependency
/// but means that if you have, e.g., two impls for the same type in
/// the same module, they do get distinct `DefId`s.
#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)]
pub struct DisambiguatedDefPathData {
pub data: DefPathData,
pub disambiguator: u32,
}
#[derive(Clone, Debug, Encodable, Decodable)]
pub struct DefPath {
/// The path leading from the crate root to the item.
pub data: Vec<DisambiguatedDefPathData>,
/// The crate root this path is relative to.
pub krate: CrateNum,
}
impl DefPath {
pub fn is_local(&self) -> bool {
self.krate == LOCAL_CRATE
}
pub fn make<FN>(krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath
where
FN: FnMut(DefIndex) -> DefKey,
{
let mut data = vec![];
let mut index = Some(start_index);
loop {
debug!("DefPath::make: krate={:?} index={:?}", krate, index);
let p = index.unwrap();
let key = get_key(p);
debug!("DefPath::make: key={:?}", key);
match key.disambiguated_data.data {
DefPathData::CrateRoot => {
assert!(key.parent.is_none());
break;
}
_ => {
data.push(key.disambiguated_data);
index = key.parent;
}
}
}
data.reverse();
DefPath { data, krate }
}
/// Returns a string representation of the `DefPath` without
/// the crate-prefix. This method is useful if you don't have
/// a `TyCtxt` available.
pub fn to_string_no_crate(&self) -> String {
let mut s = String::with_capacity(self.data.len() * 16);
for component in &self.data {
write!(s, "::{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap();
}
s
}
/// Returns a filename-friendly string for the `DefPath`, with the
/// crate-prefix.
pub fn to_string_friendly<F>(&self, crate_imported_name: F) -> String
where
F: FnOnce(CrateNum) -> Symbol,
{
let crate_name_str = crate_imported_name(self.krate).as_str();
let mut s = String::with_capacity(crate_name_str.len() + self.data.len() * 16);
write!(s, "::{}", crate_name_str).unwrap();
for component in &self.data {
if component.disambiguator == 0 {
write!(s, "::{}", component.data.as_symbol()).unwrap();
} else {
write!(s, "{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap();
}
}
s
}
/// Returns a filename-friendly string of the `DefPath`, without
/// the crate-prefix. This method is useful if you don't have
/// a `TyCtxt` available.
pub fn to_filename_friendly_no_crate(&self) -> String {
let mut s = String::with_capacity(self.data.len() * 16);
let mut opt_delimiter = None;
for component in &self.data {
s.extend(opt_delimiter);
opt_delimiter = Some('-');
if component.disambiguator == 0 {
write!(s, "{}", component.data.as_symbol()).unwrap();
} else {
write!(s, "{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap();
}
}
s
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum DefPathData {
// Root: these should only be used for the root nodes, because
// they are treated specially by the `def_path` function.
/// The crate root (marker).
CrateRoot,
// Catch-all for random `DefId` things like `DUMMY_NODE_ID`.
Misc,
// Different kinds of items and item-like things:
/// An impl.
Impl,
/// Something in the type namespace.
TypeNs(Symbol),
/// Something in the value namespace.
ValueNs(Symbol),
/// Something in the macro namespace.
MacroNs(Symbol),
/// Something in the lifetime namespace.
LifetimeNs(Symbol),
/// A closure expression.
ClosureExpr,
// Subportions of items:
/// Implicit constructor for a unit or tuple-like struct or enum variant.
Ctor,
/// A constant expression (see `{ast,hir}::AnonConst`).
AnonConst,
/// An `impl Trait` type node.
ImplTrait,
}
impl Definitions {
pub fn def_path_table(&self) -> &DefPathTable {
&self.table
}
/// Gets the number of definitions.
pub fn def_index_count(&self) -> usize {
self.table.index_to_key.len()
}
pub fn def_key(&self, id: LocalDefId) -> DefKey {
self.table.def_key(id.local_def_index)
}
#[inline(always)]
pub fn def_path_hash(&self, id: LocalDefId) -> DefPathHash {
self.table.def_path_hash(id.local_def_index)
}
/// Returns the path from the crate root to `index`. The root
/// nodes are not included in the path (i.e., this will be an
/// empty vector for the crate root). For an inlined item, this
/// will be the path of the item in the external crate (but the
/// path will begin with the path to the external crate).
pub fn def_path(&self, id: LocalDefId) -> DefPath {
DefPath::make(LOCAL_CRATE, id.local_def_index, |index| {
self.def_key(LocalDefId { local_def_index: index })
})
}
#[inline]
pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId {
self.def_id_to_hir_id[id].unwrap()
}
#[inline]
pub fn opt_local_def_id_to_hir_id(&self, id: LocalDefId) -> Option<hir::HirId> {
self.def_id_to_hir_id[id]
}
#[inline]
pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option<LocalDefId> {
self.hir_id_to_def_id.get(&hir_id).copied()
}
/// Adds a root definition (no parent) and a few other reserved definitions.
pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> Definitions {
let key = DefKey {
parent: None,
disambiguated_data: DisambiguatedDefPathData {
data: DefPathData::CrateRoot,
disambiguator: 0,
},
};
let parent_hash = DefKey::root_parent_stable_hash(crate_name, crate_disambiguator);
let def_path_hash = key.compute_stable_hash(parent_hash);
// Create the root definition.
let mut table = DefPathTable::default();
let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
Definitions {
table,
def_id_to_hir_id: Default::default(),
hir_id_to_def_id: Default::default(),
expansions_that_defined: Default::default(),
parent_modules_of_macro_defs: Default::default(),
}
}
/// Retrieves the root definition.
pub fn get_root_def(&self) -> LocalDefId {
LocalDefId { local_def_index: CRATE_DEF_INDEX }
}
/// Adds a definition with a parent definition.
pub fn create_def(
&mut self,
parent: LocalDefId,
data: DefPathData,
expn_id: ExpnId,
mut next_disambiguator: impl FnMut(LocalDefId, DefPathData) -> u32,
) -> LocalDefId {
debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id);
// The root node must be created with `create_root_def()`.
assert!(data != DefPathData::CrateRoot);
let disambiguator = next_disambiguator(parent, data);
let key = DefKey {
parent: Some(parent.local_def_index),
disambiguated_data: DisambiguatedDefPathData { data, disambiguator },
};
let parent_hash = self.table.def_path_hash(parent.local_def_index);
let def_path_hash = key.compute_stable_hash(parent_hash);
debug!("create_def: after disambiguation, key = {:?}", key);
// Create the definition.
let def_id = LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) };
if expn_id != ExpnId::root() {
self.expansions_that_defined.insert(def_id, expn_id);
}
def_id
}
/// Initializes the `LocalDefId` to `HirId` mapping once it has been generated during
/// AST to HIR lowering.
pub fn init_def_id_to_hir_id_mapping(
&mut self,
mapping: IndexVec<LocalDefId, Option<hir::HirId>>,
) {
assert!(
self.def_id_to_hir_id.is_empty(),
"trying to initialize `LocalDefId` <-> `HirId` mappings twice"
);
// Build the reverse mapping of `def_id_to_hir_id`.
self.hir_id_to_def_id = mapping
.iter_enumerated()
.filter_map(|(def_id, hir_id)| hir_id.map(|hir_id| (hir_id, def_id)))
.collect();
self.def_id_to_hir_id = mapping;
}
pub fn expansion_that_defined(&self, id: LocalDefId) -> ExpnId {
self.expansions_that_defined.get(&id).copied().unwrap_or(ExpnId::root())
}
pub fn parent_module_of_macro_def(&self, expn_id: ExpnId) -> DefId {
self.parent_modules_of_macro_defs[&expn_id]
}
pub fn add_parent_module_of_macro_def(&mut self, expn_id: ExpnId, module: DefId) {
self.parent_modules_of_macro_defs.insert(expn_id, module);
}
}
impl DefPathData {
pub fn get_opt_name(&self) -> Option<Symbol> {
use self::DefPathData::*;
match *self {
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
Impl | CrateRoot | Misc | ClosureExpr | Ctor | AnonConst | ImplTrait => None,
}
}
pub fn as_symbol(&self) -> Symbol {
use self::DefPathData::*;
match *self {
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => name,
// Note that this does not show up in user print-outs.
CrateRoot => sym::double_braced_crate,
Impl => sym::double_braced_impl,
Misc => sym::double_braced_misc,
ClosureExpr => sym::double_braced_closure,
Ctor => sym::double_braced_constructor,
AnonConst => sym::double_braced_constant,
ImplTrait => sym::double_braced_opaque,
}
}
pub fn to_string(&self) -> String {
self.as_symbol().to_string()
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,49 @@
use crate::def_id::{LocalDefId, CRATE_DEF_INDEX};
use std::fmt;
/// Uniquely identifies a node in the HIR of the current crate. It is
/// composed of the `owner`, which is the `LocalDefId` of the directly enclosing
/// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"),
/// and the `local_id` which is unique within the given owner.
///
/// This two-level structure makes for more stable values: One can move an item
/// around within the source code, or add or remove stuff before it, without
/// the `local_id` part of the `HirId` changing, which is a very useful property in
/// incremental compilation where we have to persist things through changes to
/// the code base.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
#[derive(Encodable, Decodable)]
pub struct HirId {
pub owner: LocalDefId,
pub local_id: ItemLocalId,
}
impl fmt::Display for HirId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
rustc_data_structures::define_id_collections!(HirIdMap, HirIdSet, HirId);
rustc_data_structures::define_id_collections!(ItemLocalMap, ItemLocalSet, ItemLocalId);
rustc_index::newtype_index! {
/// An `ItemLocalId` uniquely identifies something within a given "item-like";
/// that is, within a `hir::Item`, `hir::TraitItem`, or `hir::ImplItem`. There is no
/// guarantee that the numerical value of a given `ItemLocalId` corresponds to
/// the node's position within the owning item in any way, but there is a
/// guarantee that the `LocalItemId`s within an owner occupy a dense range of
/// integers starting at zero, so a mapping that maps all or most nodes within
/// an "item-like" to something else can be implemented by a `Vec` instead of a
/// tree or hash map.
pub struct ItemLocalId { .. }
}
rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId);
/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`.
pub const CRATE_HIR_ID: HirId = HirId {
owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
local_id: ItemLocalId::from_u32(0),
};
pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId::MAX;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,57 @@
use super::{ImplItem, Item, TraitItem};
/// The "item-like visitor" defines only the top-level methods
/// that can be invoked by `Crate::visit_all_item_likes()`. Whether
/// this trait is the right one to implement will depend on the
/// overall pattern you need. Here are the three available patterns,
/// in roughly the order of desirability:
///
/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
/// - Example: find all items with a `#[foo]` attribute on them.
/// - How: Implement `ItemLikeVisitor` and call `tcx.hir().krate().visit_all_item_likes()`.
/// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
/// - Con: Don't get information about nesting
/// - Con: Don't have methods for specific bits of HIR, like "on
/// every expr, do this".
/// 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within
/// an item, but don't care about how item-like things are nested
/// within one another.
/// - Example: Examine each expression to look for its type and do some check or other.
/// - How: Implement `intravisit::Visitor` and override the `nested_visit_map()` method
/// to return `NestedVisitorMap::OnlyBodies` and use
/// `tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within
/// your `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget
/// to invoke `intravisit::walk_expr()` to keep walking the subparts).
/// - Pro: Visitor methods for any kind of HIR node, not just item-like things.
/// - Pro: Integrates well into dependency tracking.
/// - Con: Don't get information about nesting between items
/// 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between
/// item-like things.
/// - Example: Lifetime resolution, which wants to bring lifetimes declared on the
/// impl into scope while visiting the impl-items, and then back out again.
/// - How: Implement `intravisit::Visitor` and override the `nested_visit_map()` method
/// to return `NestedVisitorMap::All`. Walk your crate with `intravisit::walk_crate()`
/// invoked on `tcx.hir().krate()`.
/// - Pro: Visitor methods for any kind of HIR node, not just item-like things.
/// - Pro: Preserves nesting information
/// - Con: Does not integrate well into dependency tracking.
///
/// Note: the methods of `ItemLikeVisitor` intentionally have no
/// defaults, so that as we expand the list of item-like things, we
/// revisit the various visitors to see if they need to change. This
/// is harder to do with `intravisit::Visitor`, so when you add a new
/// `visit_nested_foo()` method, it is recommended that you search for
/// existing `fn visit_nested` methods to see where changes are
/// needed.
pub trait ItemLikeVisitor<'hir> {
fn visit_item(&mut self, item: &'hir Item<'hir>);
fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>);
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>);
}
/// A parallel variant of `ItemLikeVisitor`.
pub trait ParItemLikeVisitor<'hir> {
fn visit_item(&self, item: &'hir Item<'hir>);
fn visit_trait_item(&self, trait_item: &'hir TraitItem<'hir>);
fn visit_impl_item(&self, impl_item: &'hir ImplItem<'hir>);
}

View file

@ -0,0 +1,334 @@
//! Defines language items.
//!
//! Language items are items that represent concepts intrinsic to the language
//! itself. Examples are:
//!
//! * Traits that specify "kinds"; e.g., `Sync`, `Send`.
//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
//! * Functions called by the compiler itself.
use crate::def_id::DefId;
use crate::{MethodKind, Target};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_macros::HashStable_Generic;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
use lazy_static::lazy_static;
pub enum LangItemGroup {
Op,
}
const NUM_GROUPS: usize = 1;
macro_rules! expand_group {
() => {
None
};
($group:expr) => {
Some($group)
};
}
// The actual lang items defined come at the end of this file in one handy table.
// So you probably just want to nip down to the end.
macro_rules! language_item_table {
(
$( $variant:ident $($group:expr)?, $name:expr, $method:ident, $target:expr; )*
) => {
enum_from_u32! {
/// A representation of all the valid language items in Rust.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum LangItem {
$($variant,)*
}
}
impl LangItem {
/// Returns the `name` symbol in `#[lang = "$name"]`.
/// For example, `LangItem::EqTraitLangItem`,
/// that is `#[lang = "eq"]` would result in `sym::eq`.
pub fn name(self) -> Symbol {
match self {
$( LangItem::$variant => $name, )*
}
}
pub fn group(self) -> Option<LangItemGroup> {
use LangItemGroup::*;
match self {
$( LangItem::$variant => expand_group!($($group)*), )*
}
}
}
#[derive(HashStable_Generic)]
pub struct LanguageItems {
/// Mappings from lang items to their possibly found `DefId`s.
/// The index corresponds to the order in `LangItem`.
pub items: Vec<Option<DefId>>,
/// Lang items that were not found during collection.
pub missing: Vec<LangItem>,
/// Mapping from `LangItemGroup` discriminants to all
/// `DefId`s of lang items in that group.
pub groups: [Vec<DefId>; NUM_GROUPS],
}
impl LanguageItems {
/// Construct an empty collection of lang items and no missing ones.
pub fn new() -> Self {
fn init_none(_: LangItem) -> Option<DefId> { None }
Self {
items: vec![$(init_none(LangItem::$variant)),*],
missing: Vec::new(),
groups: [vec![]; NUM_GROUPS],
}
}
/// Returns the mappings to the possibly found `DefId`s for each lang item.
pub fn items(&self) -> &[Option<DefId>] {
&*self.items
}
/// Requires that a given `LangItem` was bound and returns the corresponding `DefId`.
/// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`,
/// returns an error message as a string.
pub fn require(&self, it: LangItem) -> Result<DefId, String> {
self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
}
pub fn group(&self, group: LangItemGroup) -> &[DefId] {
self.groups[group as usize].as_ref()
}
$(
/// Returns the corresponding `DefId` for the lang item if it
/// exists.
#[allow(dead_code)]
pub fn $method(&self) -> Option<DefId> {
self.items[LangItem::$variant as usize]
}
)*
}
lazy_static! {
/// A mapping from the name of the lang item to its order and the form it must be of.
pub static ref ITEM_REFS: FxHashMap<Symbol, (usize, Target)> = {
let mut item_refs = FxHashMap::default();
$( item_refs.insert($name, (LangItem::$variant as usize, $target)); )*
item_refs
};
}
// End of the macro
}
}
impl<CTX> HashStable<CTX> for LangItem {
fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) {
::std::hash::Hash::hash(self, hasher);
}
}
/// Extracts the first `lang = "$name"` out of a list of attributes.
/// The attributes `#[panic_handler]` and `#[alloc_error_handler]`
/// are also extracted out when found.
///
/// About the `check_name` argument: passing in a `Session` would be simpler,
/// because then we could call `Session::check_name` directly. But we want to
/// avoid the need for `librustc_hir` to depend on `librustc_session`, so we
/// use a closure instead.
pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Symbol, Span)>
where
F: Fn(&'a ast::Attribute, Symbol) -> bool,
{
attrs.iter().find_map(|attr| {
Some(match attr {
_ if check_name(attr, sym::lang) => (attr.value_str()?, attr.span),
_ if check_name(attr, sym::panic_handler) => (sym::panic_impl, attr.span),
_ if check_name(attr, sym::alloc_error_handler) => (sym::oom, attr.span),
_ => return None,
})
})
}
language_item_table! {
// Variant name, Name, Method name, Target;
Bool, sym::bool, bool_impl, Target::Impl;
Char, sym::char, char_impl, Target::Impl;
Str, sym::str, str_impl, Target::Impl;
Array, sym::array, array_impl, Target::Impl;
Slice, sym::slice, slice_impl, Target::Impl;
SliceU8, sym::slice_u8, slice_u8_impl, Target::Impl;
StrAlloc, sym::str_alloc, str_alloc_impl, Target::Impl;
SliceAlloc, sym::slice_alloc, slice_alloc_impl, Target::Impl;
SliceU8Alloc, sym::slice_u8_alloc, slice_u8_alloc_impl, Target::Impl;
ConstPtr, sym::const_ptr, const_ptr_impl, Target::Impl;
MutPtr, sym::mut_ptr, mut_ptr_impl, Target::Impl;
ConstSlicePtr, sym::const_slice_ptr, const_slice_ptr_impl, Target::Impl;
MutSlicePtr, sym::mut_slice_ptr, mut_slice_ptr_impl, Target::Impl;
I8, sym::i8, i8_impl, Target::Impl;
I16, sym::i16, i16_impl, Target::Impl;
I32, sym::i32, i32_impl, Target::Impl;
I64, sym::i64, i64_impl, Target::Impl;
I128, sym::i128, i128_impl, Target::Impl;
Isize, sym::isize, isize_impl, Target::Impl;
U8, sym::u8, u8_impl, Target::Impl;
U16, sym::u16, u16_impl, Target::Impl;
U32, sym::u32, u32_impl, Target::Impl;
U64, sym::u64, u64_impl, Target::Impl;
U128, sym::u128, u128_impl, Target::Impl;
Usize, sym::usize, usize_impl, Target::Impl;
F32, sym::f32, f32_impl, Target::Impl;
F64, sym::f64, f64_impl, Target::Impl;
F32Runtime, sym::f32_runtime, f32_runtime_impl, Target::Impl;
F64Runtime, sym::f64_runtime, f64_runtime_impl, Target::Impl;
Sized, sym::sized, sized_trait, Target::Trait;
Unsize, sym::unsize, unsize_trait, Target::Trait;
// Trait injected by #[derive(PartialEq)], (i.e. "Partial EQ").
StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait;
// Trait injected by #[derive(Eq)], (i.e. "Total EQ"; no, I will not apologize).
StructuralTeq, sym::structural_teq, structural_teq_trait, Target::Trait;
Copy, sym::copy, copy_trait, Target::Trait;
Clone, sym::clone, clone_trait, Target::Trait;
Sync, sym::sync, sync_trait, Target::Trait;
DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait;
// The associated item of `trait DiscriminantKind`.
Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy;
Freeze, sym::freeze, freeze_trait, Target::Trait;
Drop, sym::drop, drop_trait, Target::Trait;
CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait;
DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait;
Add(Op), sym::add, add_trait, Target::Trait;
Sub(Op), sym::sub, sub_trait, Target::Trait;
Mul(Op), sym::mul, mul_trait, Target::Trait;
Div(Op), sym::div, div_trait, Target::Trait;
Rem(Op), sym::rem, rem_trait, Target::Trait;
Neg(Op), sym::neg, neg_trait, Target::Trait;
Not(Op), sym::not, not_trait, Target::Trait;
BitXor(Op), sym::bitxor, bitxor_trait, Target::Trait;
BitAnd(Op), sym::bitand, bitand_trait, Target::Trait;
BitOr(Op), sym::bitor, bitor_trait, Target::Trait;
Shl(Op), sym::shl, shl_trait, Target::Trait;
Shr(Op), sym::shr, shr_trait, Target::Trait;
AddAssign(Op), sym::add_assign, add_assign_trait, Target::Trait;
SubAssign(Op), sym::sub_assign, sub_assign_trait, Target::Trait;
MulAssign(Op), sym::mul_assign, mul_assign_trait, Target::Trait;
DivAssign(Op), sym::div_assign, div_assign_trait, Target::Trait;
RemAssign(Op), sym::rem_assign, rem_assign_trait, Target::Trait;
BitXorAssign(Op), sym::bitxor_assign, bitxor_assign_trait, Target::Trait;
BitAndAssign(Op), sym::bitand_assign, bitand_assign_trait, Target::Trait;
BitOrAssign(Op), sym::bitor_assign, bitor_assign_trait, Target::Trait;
ShlAssign(Op), sym::shl_assign, shl_assign_trait, Target::Trait;
ShrAssign(Op), sym::shr_assign, shr_assign_trait, Target::Trait;
Index(Op), sym::index, index_trait, Target::Trait;
IndexMut(Op), sym::index_mut, index_mut_trait, Target::Trait;
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct;
VaList, sym::va_list, va_list, Target::Struct;
Deref, sym::deref, deref_trait, Target::Trait;
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait;
Receiver, sym::receiver, receiver_trait, Target::Trait;
Fn, kw::Fn, fn_trait, Target::Trait;
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait;
FnOnce, sym::fn_once, fn_once_trait, Target::Trait;
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy;
Future, sym::future_trait, future_trait, Target::Trait;
GeneratorState, sym::generator_state, gen_state, Target::Enum;
Generator, sym::generator, gen_trait, Target::Trait;
Unpin, sym::unpin, unpin_trait, Target::Trait;
Pin, sym::pin, pin_type, Target::Struct;
PartialEq, sym::eq, eq_trait, Target::Trait;
PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait;
// A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
// various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.
//
// The `begin_unwind` lang item has a predefined symbol name and is sort of a "weak lang item"
// in the sense that a crate is not required to have it defined to use it, but a final product
// is required to define it somewhere. Additionally, there are restrictions on crates that use
// a weak lang item, but do not have it defined.
Panic, sym::panic, panic_fn, Target::Fn;
PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn;
PanicInfo, sym::panic_info, panic_info, Target::Struct;
PanicLocation, sym::panic_location, panic_location, Target::Struct;
PanicImpl, sym::panic_impl, panic_impl, Target::Fn;
// libstd panic entry point. Necessary for const eval to be able to catch it
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn;
ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn;
BoxFree, sym::box_free, box_free_fn, Target::Fn;
DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn;
Oom, sym::oom, oom, Target::Fn;
AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct;
Start, sym::start, start_fn, Target::Fn;
EhPersonality, sym::eh_personality, eh_personality, Target::Fn;
EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static;
OwnedBox, sym::owned_box, owned_box, Target::Struct;
PhantomData, sym::phantom_data, phantom_data, Target::Struct;
ManuallyDrop, sym::manually_drop, manually_drop, Target::Struct;
MaybeUninit, sym::maybe_uninit, maybe_uninit, Target::Union;
// Align offset for stride != 1; must not panic.
AlignOffset, sym::align_offset, align_offset_fn, Target::Fn;
Termination, sym::termination, termination, Target::Trait;
Try, kw::Try, try_trait, Target::Trait;
// Language items from AST lowering
TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false });
TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false });
TryIntoResult, sym::into_result, into_result_fn, Target::Method(MethodKind::Trait { body: false });
PollReady, sym::Ready, poll_ready_variant, Target::Variant;
PollPending, sym::Pending, poll_pending_variant, Target::Variant;
FromGenerator, sym::from_generator, from_generator_fn, Target::Fn;
GetContext, sym::get_context, get_context_fn, Target::Fn;
FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false });
FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false });
OptionSome, sym::Some, option_some_variant, Target::Variant;
OptionNone, sym::None, option_none_variant, Target::Variant;
ResultOk, sym::Ok, result_ok_variant, Target::Variant;
ResultErr, sym::Err, result_err_variant, Target::Variant;
IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false });
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false});
PinNewUnchecked, sym::new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent);
RangeFrom, sym::RangeFrom, range_from_struct, Target::Struct;
RangeFull, sym::RangeFull, range_full_struct, Target::Struct;
RangeInclusiveStruct, sym::RangeInclusive, range_inclusive_struct, Target::Struct;
RangeInclusiveNew, sym::range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent);
Range, sym::Range, range_struct, Target::Struct;
RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct;
RangeTo, sym::RangeTo, range_to_struct, Target::Struct;
}

View file

@ -0,0 +1,36 @@
//! HIR datatypes. See the [rustc dev guide] for more info.
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
#![feature(crate_visibility_modifier)]
#![feature(const_fn)] // For the unsizing cast on `&[]`
#![feature(const_panic)]
#![feature(in_band_lifetimes)]
#![feature(or_patterns)]
#![recursion_limit = "256"]
#[macro_use]
extern crate rustc_macros;
#[macro_use]
extern crate rustc_data_structures;
mod arena;
pub mod def;
pub mod definitions;
pub use rustc_span::def_id;
mod hir;
pub mod hir_id;
pub mod intravisit;
pub mod itemlikevisit;
pub mod lang_items;
pub mod pat_util;
mod stable_hash_impls;
mod target;
pub mod weak_lang_items;
pub use hir::*;
pub use hir_id::*;
pub use lang_items::{LangItem, LanguageItems};
pub use stable_hash_impls::HashStableContext;
pub use target::{MethodKind, Target};

View file

@ -0,0 +1,194 @@
use crate::def::{CtorOf, DefKind, Res};
use crate::def_id::DefId;
use crate::hir::{self, HirId, PatKind};
use rustc_span::symbol::Ident;
use rustc_span::Span;
use std::iter::{Enumerate, ExactSizeIterator};
pub struct EnumerateAndAdjust<I> {
enumerate: Enumerate<I>,
gap_pos: usize,
gap_len: usize,
}
impl<I> Iterator for EnumerateAndAdjust<I>
where
I: Iterator,
{
type Item = (usize, <I as Iterator>::Item);
fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
self.enumerate
.next()
.map(|(i, elem)| (if i < self.gap_pos { i } else { i + self.gap_len }, elem))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.enumerate.size_hint()
}
}
pub trait EnumerateAndAdjustIterator {
fn enumerate_and_adjust(
self,
expected_len: usize,
gap_pos: Option<usize>,
) -> EnumerateAndAdjust<Self>
where
Self: Sized;
}
impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
fn enumerate_and_adjust(
self,
expected_len: usize,
gap_pos: Option<usize>,
) -> EnumerateAndAdjust<Self>
where
Self: Sized,
{
let actual_len = self.len();
EnumerateAndAdjust {
enumerate: self.enumerate(),
gap_pos: gap_pos.unwrap_or(expected_len),
gap_len: expected_len - actual_len,
}
}
}
impl hir::Pat<'_> {
pub fn is_refutable(&self) -> bool {
match self.kind {
PatKind::Lit(_)
| PatKind::Range(..)
| PatKind::Path(hir::QPath::Resolved(Some(..), _) | hir::QPath::TypeRelative(..)) => {
true
}
PatKind::Path(hir::QPath::Resolved(_, ref path))
| PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..)
| PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => match path.res {
Res::Def(DefKind::Variant, _) => true,
_ => false,
},
PatKind::Slice(..) => true,
_ => false,
}
}
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
/// `match foo() { Some(a) => (), None => () }`
pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, Ident)) {
self.walk_always(|p| {
if let PatKind::Binding(binding_mode, _, ident, _) = p.kind {
f(binding_mode, p.hir_id, p.span, ident);
}
});
}
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
/// `match foo() { Some(a) => (), None => () }`.
///
/// When encountering an or-pattern `p_0 | ... | p_n` only `p_0` will be visited.
pub fn each_binding_or_first(
&self,
f: &mut impl FnMut(hir::BindingAnnotation, HirId, Span, Ident),
) {
self.walk(|p| match &p.kind {
PatKind::Or(ps) => {
ps[0].each_binding_or_first(f);
false
}
PatKind::Binding(bm, _, ident, _) => {
f(*bm, p.hir_id, p.span, *ident);
true
}
_ => true,
})
}
/// Checks if the pattern contains any patterns that bind something to
/// an ident, e.g., `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
pub fn contains_bindings(&self) -> bool {
self.satisfies(|p| match p.kind {
PatKind::Binding(..) => true,
_ => false,
})
}
/// Checks if the pattern contains any patterns that bind something to
/// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`,
pub fn contains_bindings_or_wild(&self) -> bool {
self.satisfies(|p| match p.kind {
PatKind::Binding(..) | PatKind::Wild => true,
_ => false,
})
}
/// Checks if the pattern satisfies the given predicate on some sub-pattern.
fn satisfies(&self, pred: impl Fn(&hir::Pat<'_>) -> bool) -> bool {
let mut satisfies = false;
self.walk_short(|p| {
if pred(p) {
satisfies = true;
false // Found one, can short circuit now.
} else {
true
}
});
satisfies
}
pub fn simple_ident(&self) -> Option<Ident> {
match self.kind {
PatKind::Binding(
hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
_,
ident,
None,
) => Some(ident),
_ => None,
}
}
/// Returns variants that are necessary to exist for the pattern to match.
pub fn necessary_variants(&self) -> Vec<DefId> {
let mut variants = vec![];
self.walk(|p| match &p.kind {
PatKind::Or(_) => false,
PatKind::Path(hir::QPath::Resolved(_, path))
| PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..)
| PatKind::Struct(hir::QPath::Resolved(_, path), ..) => {
if let Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), id) =
path.res
{
variants.push(id);
}
true
}
_ => true,
});
variants.sort();
variants.dedup();
variants
}
/// Checks if the pattern contains any `ref` or `ref mut` bindings, and if
/// yes whether it contains mutable or just immutables ones.
//
// FIXME(tschottdorf): this is problematic as the HIR is being scraped, but
// ref bindings are be implicit after #42640 (default match binding modes). See issue #44848.
pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
let mut result = None;
self.each_binding(|annotation, _, _, _| match annotation {
hir::BindingAnnotation::Ref => match result {
None | Some(hir::Mutability::Not) => result = Some(hir::Mutability::Not),
_ => {}
},
hir::BindingAnnotation::RefMut => result = Some(hir::Mutability::Mut),
_ => {}
});
result
}
}

View file

@ -0,0 +1,167 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use crate::hir::{
BodyId, Expr, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem, TraitItemId, Ty,
VisibilityKind,
};
use crate::hir_id::{HirId, ItemLocalId};
use rustc_span::def_id::{DefPathHash, LocalDefId};
/// Requirements for a `StableHashingContext` to be used in this crate.
/// This is a hack to allow using the `HashStable_Generic` derive macro
/// instead of implementing everything in librustc_middle.
pub trait HashStableContext:
rustc_ast::HashStableContext + rustc_target::HashStableContext
{
fn hash_hir_id(&mut self, _: HirId, hasher: &mut StableHasher);
fn hash_body_id(&mut self, _: BodyId, hasher: &mut StableHasher);
fn hash_reference_to_item(&mut self, _: HirId, hasher: &mut StableHasher);
fn hash_hir_mod(&mut self, _: &Mod<'_>, hasher: &mut StableHasher);
fn hash_hir_expr(&mut self, _: &Expr<'_>, hasher: &mut StableHasher);
fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher);
fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher);
fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F);
fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash;
}
impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
type KeyType = (DefPathHash, ItemLocalId);
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
let def_path_hash = hcx.local_def_path_hash(self.owner);
(def_path_hash, self.local_id)
}
}
impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for TraitItemId {
type KeyType = (DefPathHash, ItemLocalId);
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
self.hir_id.to_stable_hash_key(hcx)
}
}
impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ImplItemId {
type KeyType = (DefPathHash, ItemLocalId);
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
self.hir_id.to_stable_hash_key(hcx)
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for HirId {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
hcx.hash_hir_id(*self, hasher)
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for BodyId {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
hcx.hash_body_id(*self, hasher)
}
}
// The following implementations of HashStable for `ItemId`, `TraitItemId`, and
// `ImplItemId` deserve special attention. Normally we do not hash `NodeId`s within
// the HIR, since they just signify a HIR nodes own path. But `ItemId` et al
// are used when another item in the HIR is *referenced* and we certainly
// want to pick up on a reference changing its target, so we hash the NodeIds
// in "DefPath Mode".
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ItemId {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
hcx.hash_reference_to_item(self.id, hasher)
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItemId {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
hcx.hash_reference_to_item(self.hir_id, hasher)
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItemId {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
hcx.hash_reference_to_item(self.hir_id, hasher)
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Mod<'_> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
hcx.hash_hir_mod(self, hasher)
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Expr<'_> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
hcx.hash_hir_expr(self, hasher)
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Ty<'_> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
hcx.hash_hir_ty(self, hasher)
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for VisibilityKind<'_> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
hcx.hash_hir_visibility_kind(self, hasher)
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItem<'_> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
let TraitItem { hir_id: _, ident, ref attrs, ref generics, ref kind, span } = *self;
hcx.hash_hir_item_like(|hcx| {
ident.name.hash_stable(hcx, hasher);
attrs.hash_stable(hcx, hasher);
generics.hash_stable(hcx, hasher);
kind.hash_stable(hcx, hasher);
span.hash_stable(hcx, hasher);
});
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItem<'_> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
let ImplItem {
hir_id: _,
ident,
ref vis,
defaultness,
ref attrs,
ref generics,
ref kind,
span,
} = *self;
hcx.hash_hir_item_like(|hcx| {
ident.name.hash_stable(hcx, hasher);
vis.hash_stable(hcx, hasher);
defaultness.hash_stable(hcx, hasher);
attrs.hash_stable(hcx, hasher);
generics.hash_stable(hcx, hasher);
kind.hash_stable(hcx, hasher);
span.hash_stable(hcx, hasher);
});
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Item<'_> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
let Item { ident, ref attrs, hir_id: _, ref kind, ref vis, span } = *self;
hcx.hash_hir_item_like(|hcx| {
ident.name.hash_stable(hcx, hasher);
attrs.hash_stable(hcx, hasher);
kind.hash_stable(hcx, hasher);
vis.hash_stable(hcx, hasher);
span.hash_stable(hcx, hasher);
});
}
}

View file

@ -0,0 +1,127 @@
//! This module implements some validity checks for attributes.
//! In particular it verifies that `#[inline]` and `#[repr]` attributes are
//! attached to items that actually support them and if there are
//! conflicts between multiple such attributes attached to the same
//! item.
use crate::hir;
use crate::{Item, ItemKind, TraitItem, TraitItemKind};
use std::fmt::{self, Display};
#[derive(Copy, Clone, PartialEq)]
pub enum MethodKind {
Trait { body: bool },
Inherent,
}
#[derive(Copy, Clone, PartialEq)]
pub enum Target {
ExternCrate,
Use,
Static,
Const,
Fn,
Closure,
Mod,
ForeignMod,
GlobalAsm,
TyAlias,
OpaqueTy,
Enum,
Variant,
Struct,
Union,
Trait,
TraitAlias,
Impl,
Expression,
Statement,
AssocConst,
Method(MethodKind),
AssocTy,
ForeignFn,
ForeignStatic,
ForeignTy,
}
impl Display for Target {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match *self {
Target::ExternCrate => "extern crate",
Target::Use => "use",
Target::Static => "static item",
Target::Const => "constant item",
Target::Fn => "function",
Target::Closure => "closure",
Target::Mod => "module",
Target::ForeignMod => "foreign module",
Target::GlobalAsm => "global asm",
Target::TyAlias => "type alias",
Target::OpaqueTy => "opaque type",
Target::Enum => "enum",
Target::Variant => "enum variant",
Target::Struct => "struct",
Target::Union => "union",
Target::Trait => "trait",
Target::TraitAlias => "trait alias",
Target::Impl => "item",
Target::Expression => "expression",
Target::Statement => "statement",
Target::AssocConst => "associated const",
Target::Method(_) => "method",
Target::AssocTy => "associated type",
Target::ForeignFn => "foreign function",
Target::ForeignStatic => "foreign static item",
Target::ForeignTy => "foreign type",
}
)
}
}
impl Target {
pub fn from_item(item: &Item<'_>) -> Target {
match item.kind {
ItemKind::ExternCrate(..) => Target::ExternCrate,
ItemKind::Use(..) => Target::Use,
ItemKind::Static(..) => Target::Static,
ItemKind::Const(..) => Target::Const,
ItemKind::Fn(..) => Target::Fn,
ItemKind::Mod(..) => Target::Mod,
ItemKind::ForeignMod(..) => Target::ForeignMod,
ItemKind::GlobalAsm(..) => Target::GlobalAsm,
ItemKind::TyAlias(..) => Target::TyAlias,
ItemKind::OpaqueTy(..) => Target::OpaqueTy,
ItemKind::Enum(..) => Target::Enum,
ItemKind::Struct(..) => Target::Struct,
ItemKind::Union(..) => Target::Union,
ItemKind::Trait(..) => Target::Trait,
ItemKind::TraitAlias(..) => Target::TraitAlias,
ItemKind::Impl { .. } => Target::Impl,
}
}
pub fn from_trait_item(trait_item: &TraitItem<'_>) -> Target {
match trait_item.kind {
TraitItemKind::Const(..) => Target::AssocConst,
TraitItemKind::Fn(_, hir::TraitFn::Required(_)) => {
Target::Method(MethodKind::Trait { body: false })
}
TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => {
Target::Method(MethodKind::Trait { body: true })
}
TraitItemKind::Type(..) => Target::AssocTy,
}
}
pub fn from_foreign_item(foreign_item: &hir::ForeignItem<'_>) -> Target {
match foreign_item.kind {
hir::ForeignItemKind::Fn(..) => Target::ForeignFn,
hir::ForeignItemKind::Static(..) => Target::ForeignStatic,
hir::ForeignItemKind::Type => Target::ForeignTy,
}
}
}

View file

@ -0,0 +1,53 @@
//! Validity checking for weak lang items
use crate::def_id::DefId;
use crate::{lang_items, LangItem, LanguageItems};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_span::symbol::{sym, Symbol};
use lazy_static::lazy_static;
macro_rules! weak_lang_items {
($($name:ident, $item:ident, $sym:ident;)*) => (
lazy_static! {
pub static ref WEAK_ITEMS_REFS: FxHashMap<Symbol, LangItem> = {
let mut map = FxHashMap::default();
$(map.insert(sym::$name, LangItem::$item);)*
map
};
}
/// The `check_name` argument avoids the need for `librustc_hir` to depend on
/// `librustc_session`.
pub fn link_name<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<Symbol>
where
F: Fn(&'a ast::Attribute, Symbol) -> bool
{
lang_items::extract(check_name, attrs).and_then(|(name, _)| {
$(if name == sym::$name {
Some(sym::$sym)
} else)* {
None
}
})
}
impl LanguageItems {
pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool {
let did = Some(item_def_id);
$(self.$name() == did)||*
}
}
) }
weak_lang_items! {
panic_impl, PanicImpl, rust_begin_unwind;
eh_personality, EhPersonality, rust_eh_personality;
eh_catch_typeinfo, EhCatchTypeinfo, rust_eh_catch_typeinfo;
oom, Oom, rust_oom;
}