diff options
Diffstat (limited to 'src/librustc')
109 files changed, 0 insertions, 48428 deletions
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml deleted file mode 100644 index af2be30cc0a..00000000000 --- a/src/librustc/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc" -path = "lib.rs" -doctest = false - -[dependencies] -arena = { path = "../libarena" } -bitflags = "1.2.1" -jobserver = "0.1" -scoped-tls = "1.0" -log = { version = "0.4", features = ["release_max_level_info", "std"] } -rustc-rayon = "0.3.0" -rustc-rayon-core = "0.3.0" -polonius-engine = "0.11.0" -rustc_apfloat = { path = "../librustc_apfloat" } -rustc_attr = { path = "../librustc_attr" } -rustc_feature = { path = "../librustc_feature" } -rustc_hir = { path = "../librustc_hir" } -rustc_target = { path = "../librustc_target" } -rustc_macros = { path = "../librustc_macros" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_index = { path = "../librustc_index" } -rustc_serialize = { path = "../libserialize", package = "serialize" } -syntax = { path = "../libsyntax" } -rustc_span = { path = "../librustc_span" } -backtrace = "0.3.40" -parking_lot = "0.9" -byteorder = { version = "1.3" } -chalk-engine = { version = "0.9.0", default-features=false } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -measureme = "0.7.1" -rustc_session = { path = "../librustc_session" } diff --git a/src/librustc/README.md b/src/librustc/README.md deleted file mode 100644 index c0e5c542bdc..00000000000 --- a/src/librustc/README.md +++ /dev/null @@ -1,3 +0,0 @@ -For more information about how rustc works, see the [rustc guide]. - -[rustc guide]: https://rust-lang.github.io/rustc-guide/ diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs deleted file mode 100644 index ca55d410ceb..00000000000 --- a/src/librustc/arena.rs +++ /dev/null @@ -1,352 +0,0 @@ -use arena::{DroplessArena, TypedArena}; -use smallvec::SmallVec; -use std::cell::RefCell; -use std::marker::PhantomData; -use std::mem; -use std::ptr; -use std::slice; - -/// 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, [ - [] layouts: rustc::ty::layout::LayoutDetails, - [] generics: rustc::ty::Generics, - [] trait_def: rustc::ty::TraitDef, - [] adt_def: rustc::ty::AdtDef, - [] steal_mir: rustc::ty::steal::Steal<rustc::mir::BodyAndCache<$tcx>>, - [] mir: rustc::mir::BodyAndCache<$tcx>, - [] steal_promoted: rustc::ty::steal::Steal< - rustc_index::vec::IndexVec< - rustc::mir::Promoted, - rustc::mir::BodyAndCache<$tcx> - > - >, - [] promoted: rustc_index::vec::IndexVec< - rustc::mir::Promoted, - rustc::mir::BodyAndCache<$tcx> - >, - [decode] tables: rustc::ty::TypeckTables<$tcx>, - [decode] borrowck_result: rustc::mir::BorrowCheckResult<$tcx>, - [] const_allocs: rustc::mir::interpret::Allocation, - [] vtable_method: Option<( - rustc_hir::def_id::DefId, - rustc::ty::subst::SubstsRef<$tcx> - )>, - [few, decode] mir_keys: rustc_hir::def_id::DefIdSet, - [decode] specialization_graph: rustc::traits::specialization_graph::Graph, - [] region_scope_tree: rustc::middle::region::ScopeTree, - [] item_local_set: rustc_hir::ItemLocalSet, - [decode] mir_const_qualif: rustc_index::bit_set::BitSet<rustc::mir::Local>, - [] trait_impls_of: rustc::ty::trait_def::TraitImpls, - [] associated_items: rustc::ty::AssociatedItems, - [] dropck_outlives: - rustc::infer::canonical::Canonical<'tcx, - rustc::infer::canonical::QueryResponse<'tcx, - rustc::traits::query::DropckOutlivesResult<'tcx> - > - >, - [] normalize_projection_ty: - rustc::infer::canonical::Canonical<'tcx, - rustc::infer::canonical::QueryResponse<'tcx, - rustc::traits::query::NormalizationResult<'tcx> - > - >, - [] implied_outlives_bounds: - rustc::infer::canonical::Canonical<'tcx, - rustc::infer::canonical::QueryResponse<'tcx, - Vec<rustc::traits::query::OutlivesBound<'tcx>> - > - >, - [] type_op_subtype: - rustc::infer::canonical::Canonical<'tcx, - rustc::infer::canonical::QueryResponse<'tcx, ()> - >, - [] type_op_normalize_poly_fn_sig: - rustc::infer::canonical::Canonical<'tcx, - rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::PolyFnSig<'tcx>> - >, - [] type_op_normalize_fn_sig: - rustc::infer::canonical::Canonical<'tcx, - rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::FnSig<'tcx>> - >, - [] type_op_normalize_predicate: - rustc::infer::canonical::Canonical<'tcx, - rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::Predicate<'tcx>> - >, - [] type_op_normalize_ty: - rustc::infer::canonical::Canonical<'tcx, - rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::Ty<'tcx>> - >, - [few] crate_inherent_impls: rustc::ty::CrateInherentImpls, - [few] upstream_monomorphizations: - rustc_hir::def_id::DefIdMap< - rustc_data_structures::fx::FxHashMap< - rustc::ty::subst::SubstsRef<'tcx>, - rustc_hir::def_id::CrateNum - > - >, - [few] diagnostic_items: rustc_data_structures::fx::FxHashMap< - rustc_span::symbol::Symbol, - rustc_hir::def_id::DefId, - >, - [few] resolve_lifetimes: rustc::middle::resolve_lifetime::ResolveLifetimes, - [few] lint_levels: rustc::lint::LintLevelMap, - [few] stability_index: rustc::middle::stability::Index<'tcx>, - [few] features: rustc_feature::Features, - [few] all_traits: Vec<rustc_hir::def_id::DefId>, - [few] privacy_access_levels: rustc::middle::privacy::AccessLevels, - [few] target_features_whitelist: rustc_data_structures::fx::FxHashMap< - String, - Option<rustc_span::symbol::Symbol> - >, - [few] wasm_import_module_map: rustc_data_structures::fx::FxHashMap< - rustc_hir::def_id::DefId, - String - >, - [few] get_lib_features: rustc::middle::lib_features::LibFeatures, - [few] defined_lib_features: rustc::middle::lang_items::LanguageItems, - [few] visible_parent_map: rustc_hir::def_id::DefIdMap<rustc_hir::def_id::DefId>, - [few] foreign_module: rustc::middle::cstore::ForeignModule, - [few] foreign_modules: Vec<rustc::middle::cstore::ForeignModule>, - [few] reachable_non_generics: rustc_hir::def_id::DefIdMap< - rustc::middle::exported_symbols::SymbolExportLevel - >, - [few] crate_variances: rustc::ty::CrateVariancesMap<'tcx>, - [few] inferred_outlives_crate: rustc::ty::CratePredicatesMap<'tcx>, - [] upvars: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>, - - // Interned types - [] tys: rustc::ty::TyS<$tcx>, - - // HIR types - [few] hir_krate: rustc_hir::Crate<$tcx>, - [] arm: rustc_hir::Arm<$tcx>, - [] attribute: syntax::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>, - [] inline_asm: rustc_hir::InlineAsm<$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); - ) -} - -macro_rules! arena_for_type { - ([][$ty:ty]) => { - TypedArena<$ty> - }; - ([few $(, $attrs:ident)*][$ty:ty]) => { - PhantomData<$ty> - }; - ([$ignore:ident $(, $attrs:ident)*]$args:tt) => { - arena_for_type!([$($attrs),*]$args) - }; -} - -macro_rules! declare_arena { - ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => { - #[derive(Default)] - pub struct Arena<$tcx> { - pub dropless: DroplessArena, - drop: DropArena, - $($name: arena_for_type!($a[$ty]),)* - } - } -} - -macro_rules! which_arena_for_type { - ([][$arena:expr]) => { - Some($arena) - }; - ([few$(, $attrs:ident)*][$arena:expr]) => { - None - }; - ([$ignore:ident$(, $attrs:ident)*]$args:tt) => { - which_arena_for_type!([$($attrs),*]$args) - }; -} - -macro_rules! impl_arena_allocatable { - ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => { - $( - impl ArenaAllocatable for $ty {} - unsafe impl<$tcx> ArenaField<$tcx> for $ty { - #[inline] - fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a TypedArena<Self>> { - which_arena_for_type!($a[&_arena.$name]) - } - } - )* - } -} - -arena_types!(declare_arena, [], 'tcx); - -arena_types!(impl_arena_allocatable, [], 'tcx); - -#[marker] -pub trait ArenaAllocatable {} - -impl<T: Copy> ArenaAllocatable for T {} - -unsafe trait ArenaField<'tcx>: Sized { - /// Returns a specific arena to allocate from. - /// If `None` is returned, the `DropArena` will be used. - fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a TypedArena<Self>>; -} - -unsafe impl<'tcx, T> ArenaField<'tcx> for T { - #[inline] - default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a TypedArena<Self>> { - panic!() - } -} - -impl<'tcx> Arena<'tcx> { - #[inline] - pub fn alloc<T: ArenaAllocatable>(&self, value: T) -> &mut T { - if !mem::needs_drop::<T>() { - return self.dropless.alloc(value); - } - match <T as ArenaField<'tcx>>::arena(self) { - Some(arena) => arena.alloc(value), - None => unsafe { self.drop.alloc(value) }, - } - } - - #[inline] - pub fn alloc_slice<T: Copy>(&self, value: &[T]) -> &mut [T] { - if value.len() == 0 { - return &mut []; - } - self.dropless.alloc_slice(value) - } - - pub fn alloc_from_iter<T: ArenaAllocatable, I: IntoIterator<Item = T>>( - &'a self, - iter: I, - ) -> &'a mut [T] { - if !mem::needs_drop::<T>() { - return self.dropless.alloc_from_iter(iter); - } - match <T as ArenaField<'tcx>>::arena(self) { - Some(arena) => arena.alloc_from_iter(iter), - None => unsafe { self.drop.alloc_from_iter(iter) }, - } - } -} - -/// Calls the destructor for an object when dropped. -struct DropType { - drop_fn: unsafe fn(*mut u8), - obj: *mut u8, -} - -unsafe fn drop_for_type<T>(to_drop: *mut u8) { - std::ptr::drop_in_place(to_drop as *mut T) -} - -impl Drop for DropType { - fn drop(&mut self) { - unsafe { (self.drop_fn)(self.obj) } - } -} - -/// An arena which can be used to allocate any type. -/// Allocating in this arena is unsafe since the type system -/// doesn't know which types it contains. In order to -/// allocate safely, you must store a PhantomData<T> -/// alongside this arena for each type T you allocate. -#[derive(Default)] -struct DropArena { - /// A list of destructors to run when the arena drops. - /// Ordered so `destructors` gets dropped before the arena - /// since its destructor can reference memory in the arena. - destructors: RefCell<Vec<DropType>>, - arena: DroplessArena, -} - -impl DropArena { - #[inline] - unsafe fn alloc<T>(&self, object: T) -> &mut T { - let mem = - self.arena.alloc_raw(mem::size_of::<T>(), mem::align_of::<T>()) as *mut _ as *mut T; - // Write into uninitialized memory. - ptr::write(mem, object); - let result = &mut *mem; - // Record the destructor after doing the allocation as that may panic - // and would cause `object`'s destuctor to run twice if it was recorded before - self.destructors - .borrow_mut() - .push(DropType { drop_fn: drop_for_type::<T>, obj: result as *mut T as *mut u8 }); - result - } - - #[inline] - unsafe fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] { - let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect(); - if vec.is_empty() { - return &mut []; - } - let len = vec.len(); - - let start_ptr = self - .arena - .alloc_raw(len.checked_mul(mem::size_of::<T>()).unwrap(), mem::align_of::<T>()) - as *mut _ as *mut T; - - let mut destructors = self.destructors.borrow_mut(); - // Reserve space for the destructors so we can't panic while adding them - destructors.reserve(len); - - // Move the content to the arena by copying it and then forgetting - // the content of the SmallVec - vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); - mem::forget(vec.drain(..)); - - // Record the destructors after doing the allocation as that may panic - // and would cause `object`'s destuctor to run twice if it was recorded before - for i in 0..len { - destructors.push(DropType { - drop_fn: drop_for_type::<T>, - obj: start_ptr.offset(i as isize) as *mut u8, - }); - } - - slice::from_raw_parts_mut(start_ptr, len) - } -} diff --git a/src/librustc/benches/lib.rs b/src/librustc/benches/lib.rs deleted file mode 100644 index 237751bcbd7..00000000000 --- a/src/librustc/benches/lib.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![feature(test)] - -extern crate test; - -use test::Bencher; - -// Static/dynamic method dispatch - -struct Struct { - field: isize, -} - -trait Trait { - fn method(&self) -> isize; -} - -impl Trait for Struct { - fn method(&self) -> isize { - self.field - } -} - -#[bench] -fn trait_vtable_method_call(b: &mut Bencher) { - let s = Struct { field: 10 }; - let t = &s as &dyn Trait; - b.iter(|| t.method()); -} - -#[bench] -fn trait_static_method_call(b: &mut Bencher) { - let s = Struct { field: 10 }; - b.iter(|| s.method()); -} - -// Overhead of various match forms - -#[bench] -fn option_some(b: &mut Bencher) { - let x = Some(10); - b.iter(|| match x { - Some(y) => y, - None => 11, - }); -} - -#[bench] -fn vec_pattern(b: &mut Bencher) { - let x = [1, 2, 3, 4, 5, 6]; - b.iter(|| match x { - [1, 2, 3, ..] => 10, - _ => 11, - }); -} diff --git a/src/librustc/build.rs b/src/librustc/build.rs deleted file mode 100644 index af7723aea34..00000000000 --- a/src/librustc/build.rs +++ /dev/null @@ -1,12 +0,0 @@ -use std::env; - -fn main() { - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-env-changed=CFG_LIBDIR_RELATIVE"); - println!("cargo:rerun-if-env-changed=CFG_COMPILER_HOST_TRIPLE"); - println!("cargo:rerun-if-env-changed=RUSTC_VERIFY_LLVM_IR"); - - if env::var_os("RUSTC_VERIFY_LLVM_IR").is_some() { - println!("cargo:rustc-cfg=always_verify_llvm_ir"); - } -} diff --git a/src/librustc/dep_graph/README.md b/src/librustc/dep_graph/README.md deleted file mode 100644 index 91a06e452e5..00000000000 --- a/src/librustc/dep_graph/README.md +++ /dev/null @@ -1,4 +0,0 @@ -To learn more about how dependency tracking works in rustc, see the [rustc -guide]. - -[rustc guide]: https://rust-lang.github.io/rustc-guide/query.html diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs deleted file mode 100644 index d44c54593a6..00000000000 --- a/src/librustc/dep_graph/debug.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! Code for debugging the dep-graph. - -use super::dep_node::DepNode; -use std::error::Error; - -/// A dep-node filter goes from a user-defined string to a query over -/// nodes. Right now the format is like this: -/// -/// x & y & z -/// -/// where the format-string of the dep-node must contain `x`, `y`, and -/// `z`. -#[derive(Debug)] -pub struct DepNodeFilter { - text: String, -} - -impl DepNodeFilter { - pub fn new(text: &str) -> Self { - DepNodeFilter { text: text.trim().to_string() } - } - - /// Returns `true` if all nodes always pass the filter. - pub fn accepts_all(&self) -> bool { - self.text.is_empty() - } - - /// Tests whether `node` meets the filter, returning true if so. - pub fn test(&self, node: &DepNode) -> bool { - let debug_str = format!("{:?}", node); - self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f)) - } -} - -/// A filter like `F -> G` where `F` and `G` are valid dep-node -/// filters. This can be used to test the source/target independently. -pub struct EdgeFilter { - pub source: DepNodeFilter, - pub target: DepNodeFilter, -} - -impl EdgeFilter { - pub fn new(test: &str) -> Result<EdgeFilter, Box<dyn Error>> { - let parts: Vec<_> = test.split("->").collect(); - if parts.len() != 2 { - Err(format!("expected a filter like `a&b -> c&d`, not `{}`", test).into()) - } else { - Ok(EdgeFilter { - source: DepNodeFilter::new(parts[0]), - target: DepNodeFilter::new(parts[1]), - }) - } - } - - pub fn test(&self, source: &DepNode, target: &DepNode) -> bool { - self.source.test(source) && self.target.test(target) - } -} diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs deleted file mode 100644 index eb7e2871bfc..00000000000 --- a/src/librustc/dep_graph/dep_node.rs +++ /dev/null @@ -1,533 +0,0 @@ -//! This module defines the `DepNode` type which the compiler uses to represent -//! nodes in the dependency graph. A `DepNode` consists of a `DepKind` (which -//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc) -//! and a `Fingerprint`, a 128 bit hash value the exact meaning of which -//! depends on the node's `DepKind`. Together, the kind and the fingerprint -//! fully identify a dependency node, even across multiple compilation sessions. -//! In other words, the value of the fingerprint does not depend on anything -//! that is specific to a given compilation session, like an unpredictable -//! interning key (e.g., NodeId, DefId, Symbol) or the numeric value of a -//! pointer. The concept behind this could be compared to how git commit hashes -//! uniquely identify a given commit and has a few advantages: -//! -//! * A `DepNode` can simply be serialized to disk and loaded in another session -//! without the need to do any "rebasing (like we have to do for Spans and -//! NodeIds) or "retracing" like we had to do for `DefId` in earlier -//! implementations of the dependency graph. -//! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to -//! implement `Copy`, `Sync`, `Send`, `Freeze`, etc. -//! * Since we just have a bit pattern, `DepNode` can be mapped from disk into -//! memory without any post-processing (e.g., "abomination-style" pointer -//! reconstruction). -//! * Because a `DepNode` is self-contained, we can instantiate `DepNodes` that -//! refer to things that do not exist anymore. In previous implementations -//! `DepNode` contained a `DefId`. A `DepNode` referring to something that -//! had been removed between the previous and the current compilation session -//! could not be instantiated because the current compilation session -//! contained no `DefId` for thing that had been removed. -//! -//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro -//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The -//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at -//! runtime in order to construct a valid `DepNode` fingerprint. -//! -//! Because the macro sees what parameters a given `DepKind` requires, it can -//! "infer" some properties for each kind of `DepNode`: -//! -//! * Whether a `DepNode` of a given kind has any parameters at all. Some -//! `DepNode`s, like `AllLocalTraitImpls`, represent global concepts with only one value. -//! * Whether it is possible, in principle, to reconstruct a query key from a -//! given `DepNode`. Many `DepKind`s only require a single `DefId` parameter, -//! in which case it is possible to map the node's fingerprint back to the -//! `DefId` it was computed from. In other cases, too much information gets -//! lost during fingerprint computation. -//! -//! The `DepConstructor` enum, together with `DepNode::new()` ensures that only -//! valid `DepNode` instances can be constructed. For example, the API does not -//! allow for constructing parameterless `DepNode`s with anything other -//! than a zeroed out fingerprint. More generally speaking, it relieves the -//! user of the `DepNode` API of having to know how to compute the expected -//! fingerprint for a given set of node parameters. - -use crate::hir::map::DefPathHash; -use crate::ich::{Fingerprint, StableHashingContext}; -use crate::mir; -use crate::mir::interpret::{GlobalId, LitToConstInput}; -use crate::traits; -use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, -}; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; -use rustc_hir::HirId; -use rustc_span::symbol::Symbol; -use std::fmt; -use std::hash::Hash; - -// erase!() just makes tokens go away. It's used to specify which macro argument -// is repeated (i.e., which sub-expression of the macro we are in) but don't need -// to actually use any of the arguments. -macro_rules! erase { - ($x:tt) => {{}}; -} - -macro_rules! is_anon_attr { - (anon) => { - true - }; - ($attr:ident) => { - false - }; -} - -macro_rules! is_eval_always_attr { - (eval_always) => { - true - }; - ($attr:ident) => { - false - }; -} - -macro_rules! contains_anon_attr { - ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false}); -} - -macro_rules! contains_eval_always_attr { - ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false}); -} - -macro_rules! define_dep_nodes { - (<$tcx:tt> - $( - [$($attrs:tt)*] - $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* - ,)* - ) => ( - #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, - RustcEncodable, RustcDecodable)] - pub enum DepKind { - $($variant),* - } - - impl DepKind { - #[allow(unreachable_code)] - pub fn can_reconstruct_query_key<$tcx>(&self) -> bool { - match *self { - $( - DepKind :: $variant => { - if contains_anon_attr!($($attrs)*) { - return false; - } - - // tuple args - $({ - return <$tuple_arg_ty as DepNodeParams> - ::CAN_RECONSTRUCT_QUERY_KEY; - })* - - true - } - )* - } - } - - pub fn is_anon(&self) -> bool { - match *self { - $( - DepKind :: $variant => { contains_anon_attr!($($attrs)*) } - )* - } - } - - pub fn is_eval_always(&self) -> bool { - match *self { - $( - DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) } - )* - } - } - - #[allow(unreachable_code)] - pub fn has_params(&self) -> bool { - match *self { - $( - DepKind :: $variant => { - // tuple args - $({ - erase!($tuple_arg_ty); - return true; - })* - - false - } - )* - } - } - } - - pub struct DepConstructor; - - impl DepConstructor { - $( - #[inline(always)] - #[allow(unreachable_code, non_snake_case)] - pub fn $variant<'tcx>(_tcx: TyCtxt<'tcx>, $(arg: $tuple_arg_ty)*) -> DepNode { - // tuple args - $({ - erase!($tuple_arg_ty); - let hash = DepNodeParams::to_fingerprint(&arg, _tcx); - let dep_node = DepNode { - kind: DepKind::$variant, - hash - }; - - #[cfg(debug_assertions)] - { - if !dep_node.kind.can_reconstruct_query_key() && - (_tcx.sess.opts.debugging_opts.incremental_info || - _tcx.sess.opts.debugging_opts.query_dep_graph) - { - _tcx.dep_graph.register_dep_node_debug_str(dep_node, || { - arg.to_debug_str(_tcx) - }); - } - } - - return dep_node; - })* - - DepNode { - kind: DepKind::$variant, - hash: Fingerprint::ZERO, - } - } - )* - } - - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, - RustcEncodable, RustcDecodable)] - pub struct DepNode { - pub kind: DepKind, - pub hash: Fingerprint, - } - - impl DepNode { - /// Construct a DepNode from the given DepKind and DefPathHash. This - /// method will assert that the given DepKind actually requires a - /// single DefId/DefPathHash parameter. - pub fn from_def_path_hash(kind: DepKind, - def_path_hash: DefPathHash) - -> DepNode { - debug_assert!(kind.can_reconstruct_query_key() && kind.has_params()); - DepNode { - kind, - hash: def_path_hash.0, - } - } - - /// Creates a new, parameterless DepNode. This method will assert - /// that the DepNode corresponding to the given DepKind actually - /// does not require any parameters. - pub fn new_no_params(kind: DepKind) -> DepNode { - debug_assert!(!kind.has_params()); - DepNode { - kind, - hash: Fingerprint::ZERO, - } - } - - /// Extracts the DefId corresponding to this DepNode. This will work - /// if two conditions are met: - /// - /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and - /// 2. the item that the DefPath refers to exists in the current tcx. - /// - /// Condition (1) is determined by the DepKind variant of the - /// DepNode. Condition (2) might not be fulfilled if a DepNode - /// refers to something from the previous compilation session that - /// has been removed. - pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> { - if self.kind.can_reconstruct_query_key() { - let def_path_hash = DefPathHash(self.hash); - tcx.def_path_hash_to_def_id.as_ref()? - .get(&def_path_hash).cloned() - } else { - None - } - } - - /// Used in testing - pub fn from_label_string(label: &str, - def_path_hash: DefPathHash) - -> Result<DepNode, ()> { - let kind = match label { - $( - stringify!($variant) => DepKind::$variant, - )* - _ => return Err(()), - }; - - if !kind.can_reconstruct_query_key() { - return Err(()); - } - - if kind.has_params() { - Ok(def_path_hash.to_dep_node(kind)) - } else { - Ok(DepNode::new_no_params(kind)) - } - } - - /// Used in testing - pub fn has_label_string(label: &str) -> bool { - match label { - $( - stringify!($variant) => true, - )* - _ => false, - } - } - } - - /// Contains variant => str representations for constructing - /// DepNode groups for tests. - #[allow(dead_code, non_upper_case_globals)] - pub mod label_strs { - $( - pub const $variant: &str = stringify!($variant); - )* - } - ); -} - -impl fmt::Debug for DepNode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.kind)?; - - if !self.kind.has_params() && !self.kind.is_anon() { - return Ok(()); - } - - write!(f, "(")?; - - crate::ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - if let Some(def_id) = self.extract_def_id(tcx) { - write!(f, "{}", tcx.def_path_debug_str(def_id))?; - } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) { - write!(f, "{}", s)?; - } else { - write!(f, "{}", self.hash)?; - } - } else { - write!(f, "{}", self.hash)?; - } - Ok(()) - })?; - - write!(f, ")") - } -} - -impl DefPathHash { - pub fn to_dep_node(self, kind: DepKind) -> DepNode { - DepNode::from_def_path_hash(kind, self) - } -} - -rustc_dep_node_append!([define_dep_nodes!][ <'tcx> - // We use this for most things when incr. comp. is turned off. - [] Null, - - // Represents the body of a function or method. The def-id is that of the - // function/method. - [eval_always] HirBody(DefId), - - // Represents the HIR node with the given node-id - [eval_always] Hir(DefId), - - // Represents metadata from an extern crate. - [eval_always] CrateMetadata(CrateNum), - - [eval_always] AllLocalTraitImpls, - - [anon] TraitSelect, - - [] CompileCodegenUnit(Symbol), - - [eval_always] Analysis(CrateNum), -]); - -pub trait RecoverKey<'tcx>: Sized { - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>; -} - -impl RecoverKey<'tcx> for CrateNum { - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { - dep_node.extract_def_id(tcx).map(|id| id.krate) - } -} - -impl RecoverKey<'tcx> for DefId { - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { - dep_node.extract_def_id(tcx) - } -} - -impl RecoverKey<'tcx> for DefIndex { - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { - dep_node.extract_def_id(tcx).map(|id| id.index) - } -} - -trait DepNodeParams<'tcx>: fmt::Debug { - const CAN_RECONSTRUCT_QUERY_KEY: bool; - - /// This method turns the parameters of a DepNodeConstructor into an opaque - /// Fingerprint to be used in DepNode. - /// Not all DepNodeParams support being turned into a Fingerprint (they - /// don't need to if the corresponding DepNode is anonymous). - fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { - panic!("Not implemented. Accidentally called on anonymous node?") - } - - fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { - format!("{:?}", self) - } -} - -impl<'tcx, T> DepNodeParams<'tcx> for T -where - T: HashStable<StableHashingContext<'tcx>> + fmt::Debug, -{ - default const CAN_RECONSTRUCT_QUERY_KEY: bool = false; - - default fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { - let mut hcx = tcx.create_stable_hashing_context(); - let mut hasher = StableHasher::new(); - - self.hash_stable(&mut hcx, &mut hasher); - - hasher.finish() - } - - default fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { - format!("{:?}", *self) - } -} - -impl<'tcx> DepNodeParams<'tcx> for DefId { - const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - tcx.def_path_hash(*self).0 - } - - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - tcx.def_path_str(*self) - } -} - -impl<'tcx> DepNodeParams<'tcx> for DefIndex { - const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - tcx.hir().definitions().def_path_hash(*self).0 - } - - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - tcx.def_path_str(DefId::local(*self)) - } -} - -impl<'tcx> DepNodeParams<'tcx> for CrateNum { - const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; - tcx.def_path_hash(def_id).0 - } - - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - tcx.crate_name(*self).to_string() - } -} - -impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) { - const CAN_RECONSTRUCT_QUERY_KEY: bool = false; - - // We actually would not need to specialize the implementation of this - // method but it's faster to combine the hashes than to instantiate a full - // hashing context and stable-hashing state. - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - let (def_id_0, def_id_1) = *self; - - let def_path_hash_0 = tcx.def_path_hash(def_id_0); - let def_path_hash_1 = tcx.def_path_hash(def_id_1); - - def_path_hash_0.0.combine(def_path_hash_1.0) - } - - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - let (def_id_0, def_id_1) = *self; - - format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1)) - } -} - -impl<'tcx> DepNodeParams<'tcx> for HirId { - const CAN_RECONSTRUCT_QUERY_KEY: bool = false; - - // We actually would not need to specialize the implementation of this - // method but it's faster to combine the hashes than to instantiate a full - // hashing context and stable-hashing state. - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - let HirId { owner, local_id } = *self; - - let def_path_hash = tcx.def_path_hash(DefId::local(owner)); - let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into()); - - def_path_hash.0.combine(local_id) - } -} - -/// A "work product" corresponds to a `.o` (or other) file that we -/// save in between runs. These IDs do not have a `DefId` but rather -/// some independent path or string that persists between runs without -/// the need to be mapped or unmapped. (This ensures we can serialize -/// them even in the absence of a tcx.) -#[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub struct WorkProductId { - hash: Fingerprint, -} - -impl WorkProductId { - pub fn from_cgu_name(cgu_name: &str) -> WorkProductId { - let mut hasher = StableHasher::new(); - cgu_name.len().hash(&mut hasher); - cgu_name.hash(&mut hasher); - WorkProductId { hash: hasher.finish() } - } - - pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId { - WorkProductId { hash: fingerprint } - } -} diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs deleted file mode 100644 index 531a45b120c..00000000000 --- a/src/librustc/dep_graph/graph.rs +++ /dev/null @@ -1,1198 +0,0 @@ -use crate::ty::{self, TyCtxt}; -use parking_lot::{Condvar, Mutex}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::profiling::QueryInvocationId; -use rustc_data_structures::sharded::{self, Sharded}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; -use rustc_errors::Diagnostic; -use rustc_hir::def_id::DefId; -use rustc_index::vec::{Idx, IndexVec}; -use smallvec::SmallVec; -use std::collections::hash_map::Entry; -use std::env; -use std::hash::Hash; -use std::mem; -use std::sync::atomic::Ordering::Relaxed; - -use crate::ich::{Fingerprint, StableHashingContext, StableHashingContextProvider}; - -use super::debug::EdgeFilter; -use super::dep_node::{DepKind, DepNode, WorkProductId}; -use super::prev::PreviousDepGraph; -use super::query::DepGraphQuery; -use super::safe::DepGraphSafe; -use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; - -#[derive(Clone)] -pub struct DepGraph { - data: Option<Lrc<DepGraphData>>, - - /// This field is used for assigning DepNodeIndices when running in - /// non-incremental mode. Even in non-incremental mode we make sure that - /// each task has a `DepNodeIndex` that uniquely identifies it. This unique - /// ID is used for self-profiling. - virtual_dep_node_index: Lrc<AtomicU32>, -} - -rustc_index::newtype_index! { - pub struct DepNodeIndex { .. } -} - -impl DepNodeIndex { - pub const INVALID: DepNodeIndex = DepNodeIndex::MAX; -} - -impl std::convert::From<DepNodeIndex> for QueryInvocationId { - #[inline] - fn from(dep_node_index: DepNodeIndex) -> Self { - QueryInvocationId(dep_node_index.as_u32()) - } -} - -#[derive(PartialEq)] -pub enum DepNodeColor { - Red, - Green(DepNodeIndex), -} - -impl DepNodeColor { - pub fn is_green(self) -> bool { - match self { - DepNodeColor::Red => false, - DepNodeColor::Green(_) => true, - } - } -} - -struct DepGraphData { - /// The new encoding of the dependency graph, optimized for red/green - /// tracking. The `current` field is the dependency graph of only the - /// current compilation session: We don't merge the previous dep-graph into - /// current one anymore. - current: CurrentDepGraph, - - /// The dep-graph from the previous compilation session. It contains all - /// nodes and edges as well as all fingerprints of nodes that have them. - previous: PreviousDepGraph, - - colors: DepNodeColorMap, - - /// A set of loaded diagnostics that is in the progress of being emitted. - emitting_diagnostics: Mutex<FxHashSet<DepNodeIndex>>, - - /// Used to wait for diagnostics to be emitted. - emitting_diagnostics_cond_var: Condvar, - - /// When we load, there may be `.o` files, cached MIR, or other such - /// things available to us. If we find that they are not dirty, we - /// load the path to the file storing those work-products here into - /// this map. We can later look for and extract that data. - previous_work_products: FxHashMap<WorkProductId, WorkProduct>, - - dep_node_debug: Lock<FxHashMap<DepNode, String>>, -} - -pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Option<Fingerprint> -where - R: for<'a> HashStable<StableHashingContext<'a>>, -{ - let mut stable_hasher = StableHasher::new(); - result.hash_stable(hcx, &mut stable_hasher); - - Some(stable_hasher.finish()) -} - -impl DepGraph { - pub fn new( - prev_graph: PreviousDepGraph, - prev_work_products: FxHashMap<WorkProductId, WorkProduct>, - ) -> DepGraph { - let prev_graph_node_count = prev_graph.node_count(); - - DepGraph { - data: Some(Lrc::new(DepGraphData { - previous_work_products: prev_work_products, - dep_node_debug: Default::default(), - current: CurrentDepGraph::new(prev_graph_node_count), - emitting_diagnostics: Default::default(), - emitting_diagnostics_cond_var: Condvar::new(), - previous: prev_graph, - colors: DepNodeColorMap::new(prev_graph_node_count), - })), - virtual_dep_node_index: Lrc::new(AtomicU32::new(0)), - } - } - - pub fn new_disabled() -> DepGraph { - DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) } - } - - /// Returns `true` if we are actually building the full dep-graph, and `false` otherwise. - #[inline] - pub fn is_fully_enabled(&self) -> bool { - self.data.is_some() - } - - pub fn query(&self) -> DepGraphQuery { - let data = self.data.as_ref().unwrap().current.data.lock(); - let nodes: Vec<_> = data.iter().map(|n| n.node).collect(); - let mut edges = Vec::new(); - for (from, edge_targets) in data.iter().map(|d| (d.node, &d.edges)) { - for &edge_target in edge_targets.iter() { - let to = data[edge_target].node; - edges.push((from, to)); - } - } - - DepGraphQuery::new(&nodes[..], &edges[..]) - } - - pub fn assert_ignored(&self) { - if let Some(..) = self.data { - ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; - assert!(icx.task_deps.is_none(), "expected no task dependency tracking"); - }) - } - } - - pub fn with_ignore<OP, R>(&self, op: OP) -> R - where - OP: FnOnce() -> R, - { - ty::tls::with_context(|icx| { - let icx = ty::tls::ImplicitCtxt { task_deps: None, ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| op()) - }) - } - - /// Starts a new dep-graph task. Dep-graph tasks are specified - /// using a free function (`task`) and **not** a closure -- this - /// is intentional because we want to exercise tight control over - /// what state they have access to. In particular, we want to - /// prevent implicit 'leaks' of tracked state into the task (which - /// could then be read without generating correct edges in the - /// dep-graph -- see the [rustc guide] for more details on - /// the dep-graph). To this end, the task function gets exactly two - /// pieces of state: the context `cx` and an argument `arg`. Both - /// of these bits of state must be of some type that implements - /// `DepGraphSafe` and hence does not leak. - /// - /// The choice of two arguments is not fundamental. One argument - /// would work just as well, since multiple values can be - /// collected using tuples. However, using two arguments works out - /// to be quite convenient, since it is common to need a context - /// (`cx`) and some argument (e.g., a `DefId` identifying what - /// item to process). - /// - /// For cases where you need some other number of arguments: - /// - /// - If you only need one argument, just use `()` for the `arg` - /// parameter. - /// - If you need 3+ arguments, use a tuple for the - /// `arg` parameter. - /// - /// [rustc guide]: https://rust-lang.github.io/rustc-guide/incremental-compilation.html - pub fn with_task<'a, C, A, R>( - &self, - key: DepNode, - cx: C, - arg: A, - task: fn(C, A) -> R, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>, - ) -> (R, DepNodeIndex) - where - C: DepGraphSafe + StableHashingContextProvider<'a>, - { - self.with_task_impl( - key, - cx, - arg, - false, - task, - |_key| { - Some(TaskDeps { - #[cfg(debug_assertions)] - node: Some(_key), - reads: SmallVec::new(), - read_set: Default::default(), - }) - }, - |data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint), - hash_result, - ) - } - - /// Creates a new dep-graph input with value `input` - pub fn input_task<'a, C, R>(&self, key: DepNode, cx: C, input: R) -> (R, DepNodeIndex) - where - C: DepGraphSafe + StableHashingContextProvider<'a>, - R: for<'b> HashStable<StableHashingContext<'b>>, - { - fn identity_fn<C, A>(_: C, arg: A) -> A { - arg - } - - self.with_task_impl( - key, - cx, - input, - true, - identity_fn, - |_| None, - |data, key, fingerprint, _| data.alloc_node(key, SmallVec::new(), fingerprint), - hash_result::<R>, - ) - } - - fn with_task_impl<'a, C, A, R>( - &self, - key: DepNode, - cx: C, - arg: A, - no_tcx: bool, - task: fn(C, A) -> R, - create_task: fn(DepNode) -> Option<TaskDeps>, - finish_task_and_alloc_depnode: fn( - &CurrentDepGraph, - DepNode, - Fingerprint, - Option<TaskDeps>, - ) -> DepNodeIndex, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>, - ) -> (R, DepNodeIndex) - where - C: DepGraphSafe + StableHashingContextProvider<'a>, - { - if let Some(ref data) = self.data { - let task_deps = create_task(key).map(|deps| Lock::new(deps)); - - // In incremental mode, hash the result of the task. We don't - // do anything with the hash yet, but we are computing it - // anyway so that - // - we make sure that the infrastructure works and - // - we can get an idea of the runtime cost. - let mut hcx = cx.get_stable_hashing_context(); - - let result = if no_tcx { - task(cx, arg) - } else { - ty::tls::with_context(|icx| { - let icx = - ty::tls::ImplicitCtxt { task_deps: task_deps.as_ref(), ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| task(cx, arg)) - }) - }; - - let current_fingerprint = hash_result(&mut hcx, &result); - - let dep_node_index = finish_task_and_alloc_depnode( - &data.current, - key, - current_fingerprint.unwrap_or(Fingerprint::ZERO), - task_deps.map(|lock| lock.into_inner()), - ); - - let print_status = cfg!(debug_assertions) && hcx.sess().opts.debugging_opts.dep_tasks; - - // Determine the color of the new DepNode. - if let Some(prev_index) = data.previous.node_to_index_opt(&key) { - let prev_fingerprint = data.previous.fingerprint_by_index(prev_index); - - let color = if let Some(current_fingerprint) = current_fingerprint { - if current_fingerprint == prev_fingerprint { - if print_status { - eprintln!("[task::green] {:?}", key); - } - DepNodeColor::Green(dep_node_index) - } else { - if print_status { - eprintln!("[task::red] {:?}", key); - } - DepNodeColor::Red - } - } else { - if print_status { - eprintln!("[task::unknown] {:?}", key); - } - // Mark the node as Red if we can't hash the result - DepNodeColor::Red - }; - - debug_assert!( - data.colors.get(prev_index).is_none(), - "DepGraph::with_task() - Duplicate DepNodeColor \ - insertion for {:?}", - key - ); - - data.colors.insert(prev_index, color); - } else { - if print_status { - eprintln!("[task::new] {:?}", key); - } - } - - (result, dep_node_index) - } else { - (task(cx, arg), self.next_virtual_depnode_index()) - } - } - - /// Executes something within an "anonymous" task, that is, a task the - /// `DepNode` of which is determined by the list of inputs it read from. - pub fn with_anon_task<OP, R>(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeIndex) - where - OP: FnOnce() -> R, - { - if let Some(ref data) = self.data { - let (result, task_deps) = ty::tls::with_context(|icx| { - let task_deps = Lock::new(TaskDeps { - #[cfg(debug_assertions)] - node: None, - reads: SmallVec::new(), - read_set: Default::default(), - }); - - let r = { - let icx = ty::tls::ImplicitCtxt { task_deps: Some(&task_deps), ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| op()) - }; - - (r, task_deps.into_inner()) - }); - let dep_node_index = data.current.complete_anon_task(dep_kind, task_deps); - (result, dep_node_index) - } else { - (op(), self.next_virtual_depnode_index()) - } - } - - /// Executes something within an "eval-always" task which is a task - /// that runs whenever anything changes. - pub fn with_eval_always_task<'a, C, A, R>( - &self, - key: DepNode, - cx: C, - arg: A, - task: fn(C, A) -> R, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>, - ) -> (R, DepNodeIndex) - where - C: DepGraphSafe + StableHashingContextProvider<'a>, - { - self.with_task_impl( - key, - cx, - arg, - false, - task, - |_| None, - |data, key, fingerprint, _| data.alloc_node(key, smallvec![], fingerprint), - hash_result, - ) - } - - #[inline] - pub fn read(&self, v: DepNode) { - if let Some(ref data) = self.data { - let map = data.current.node_to_node_index.get_shard_by_value(&v).lock(); - if let Some(dep_node_index) = map.get(&v).copied() { - std::mem::drop(map); - data.read_index(dep_node_index); - } else { - bug!("DepKind {:?} should be pre-allocated but isn't.", v.kind) - } - } - } - - #[inline] - pub fn read_index(&self, dep_node_index: DepNodeIndex) { - if let Some(ref data) = self.data { - data.read_index(dep_node_index); - } - } - - #[inline] - pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { - self.data - .as_ref() - .unwrap() - .current - .node_to_node_index - .get_shard_by_value(dep_node) - .lock() - .get(dep_node) - .cloned() - .unwrap() - } - - #[inline] - pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { - if let Some(ref data) = self.data { - data.current - .node_to_node_index - .get_shard_by_value(&dep_node) - .lock() - .contains_key(dep_node) - } else { - false - } - } - - #[inline] - pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint { - let data = self.data.as_ref().expect("dep graph enabled").current.data.lock(); - data[dep_node_index].fingerprint - } - - pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> { - self.data.as_ref().unwrap().previous.fingerprint_of(dep_node) - } - - #[inline] - pub fn prev_dep_node_index_of(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { - self.data.as_ref().unwrap().previous.node_to_index(dep_node) - } - - /// Checks whether a previous work product exists for `v` and, if - /// so, return the path that leads to it. Used to skip doing work. - pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> { - self.data.as_ref().and_then(|data| data.previous_work_products.get(v).cloned()) - } - - /// Access the map of work-products created during the cached run. Only - /// used during saving of the dep-graph. - pub fn previous_work_products(&self) -> &FxHashMap<WorkProductId, WorkProduct> { - &self.data.as_ref().unwrap().previous_work_products - } - - #[inline(always)] - pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode, debug_str_gen: F) - where - F: FnOnce() -> String, - { - let dep_node_debug = &self.data.as_ref().unwrap().dep_node_debug; - - if dep_node_debug.borrow().contains_key(&dep_node) { - return; - } - let debug_str = debug_str_gen(); - dep_node_debug.borrow_mut().insert(dep_node, debug_str); - } - - pub(super) fn dep_node_debug_str(&self, dep_node: DepNode) -> Option<String> { - self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned() - } - - pub fn edge_deduplication_data(&self) -> Option<(u64, u64)> { - if cfg!(debug_assertions) { - let current_dep_graph = &self.data.as_ref().unwrap().current; - - Some(( - current_dep_graph.total_read_count.load(Relaxed), - current_dep_graph.total_duplicate_read_count.load(Relaxed), - )) - } else { - None - } - } - - pub fn serialize(&self) -> SerializedDepGraph { - let data = self.data.as_ref().unwrap().current.data.lock(); - - let fingerprints: IndexVec<SerializedDepNodeIndex, _> = - data.iter().map(|d| d.fingerprint).collect(); - let nodes: IndexVec<SerializedDepNodeIndex, _> = data.iter().map(|d| d.node).collect(); - - let total_edge_count: usize = data.iter().map(|d| d.edges.len()).sum(); - - let mut edge_list_indices = IndexVec::with_capacity(nodes.len()); - let mut edge_list_data = Vec::with_capacity(total_edge_count); - - for (current_dep_node_index, edges) in data.iter_enumerated().map(|(i, d)| (i, &d.edges)) { - let start = edge_list_data.len() as u32; - // This should really just be a memcpy :/ - edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex::new(i.index()))); - let end = edge_list_data.len() as u32; - - debug_assert_eq!(current_dep_node_index.index(), edge_list_indices.len()); - edge_list_indices.push((start, end)); - } - - debug_assert!(edge_list_data.len() <= ::std::u32::MAX as usize); - debug_assert_eq!(edge_list_data.len(), total_edge_count); - - SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data } - } - - pub fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> { - if let Some(ref data) = self.data { - if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { - return data.colors.get(prev_index); - } else { - // This is a node that did not exist in the previous compilation - // session, so we consider it to be red. - return Some(DepNodeColor::Red); - } - } - - None - } - - /// Try to read a node index for the node dep_node. - /// A node will have an index, when it's already been marked green, or when we can mark it - /// green. This function will mark the current task as a reader of the specified node, when - /// a node index can be found for that node. - pub fn try_mark_green_and_read( - &self, - tcx: TyCtxt<'_>, - dep_node: &DepNode, - ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { - self.try_mark_green(tcx, dep_node).map(|(prev_index, dep_node_index)| { - debug_assert!(self.is_green(&dep_node)); - self.read_index(dep_node_index); - (prev_index, dep_node_index) - }) - } - - pub fn try_mark_green( - &self, - tcx: TyCtxt<'_>, - dep_node: &DepNode, - ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { - debug_assert!(!dep_node.kind.is_eval_always()); - - // Return None if the dep graph is disabled - let data = self.data.as_ref()?; - - // Return None if the dep node didn't exist in the previous session - let prev_index = data.previous.node_to_index_opt(dep_node)?; - - match data.colors.get(prev_index) { - Some(DepNodeColor::Green(dep_node_index)) => Some((prev_index, dep_node_index)), - Some(DepNodeColor::Red) => None, - None => { - // This DepNode and the corresponding query invocation existed - // in the previous compilation session too, so we can try to - // mark it as green by recursively marking all of its - // dependencies green. - self.try_mark_previous_green(tcx, data, prev_index, &dep_node) - .map(|dep_node_index| (prev_index, dep_node_index)) - } - } - } - - /// Try to mark a dep-node which existed in the previous compilation session as green. - fn try_mark_previous_green<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - data: &DepGraphData, - prev_dep_node_index: SerializedDepNodeIndex, - dep_node: &DepNode, - ) -> Option<DepNodeIndex> { - debug!("try_mark_previous_green({:?}) - BEGIN", dep_node); - - #[cfg(not(parallel_compiler))] - { - debug_assert!( - !data - .current - .node_to_node_index - .get_shard_by_value(dep_node) - .lock() - .contains_key(dep_node) - ); - debug_assert!(data.colors.get(prev_dep_node_index).is_none()); - } - - // We never try to mark eval_always nodes as green - debug_assert!(!dep_node.kind.is_eval_always()); - - debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node); - - let prev_deps = data.previous.edge_targets_from(prev_dep_node_index); - - let mut current_deps = SmallVec::new(); - - for &dep_dep_node_index in prev_deps { - let dep_dep_node_color = data.colors.get(dep_dep_node_index); - - match dep_dep_node_color { - Some(DepNodeColor::Green(node_index)) => { - // This dependency has been marked as green before, we are - // still fine and can continue with checking the other - // dependencies. - debug!( - "try_mark_previous_green({:?}) --- found dependency {:?} to \ - be immediately green", - dep_node, - data.previous.index_to_node(dep_dep_node_index) - ); - current_deps.push(node_index); - } - Some(DepNodeColor::Red) => { - // We found a dependency the value of which has changed - // compared to the previous compilation session. We cannot - // mark the DepNode as green and also don't need to bother - // with checking any of the other dependencies. - debug!( - "try_mark_previous_green({:?}) - END - dependency {:?} was \ - immediately red", - dep_node, - data.previous.index_to_node(dep_dep_node_index) - ); - return None; - } - None => { - let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); - - // We don't know the state of this dependency. If it isn't - // an eval_always node, let's try to mark it green recursively. - if !dep_dep_node.kind.is_eval_always() { - debug!( - "try_mark_previous_green({:?}) --- state of dependency {:?} \ - is unknown, trying to mark it green", - dep_node, dep_dep_node - ); - - let node_index = self.try_mark_previous_green( - tcx, - data, - dep_dep_node_index, - dep_dep_node, - ); - if let Some(node_index) = node_index { - debug!( - "try_mark_previous_green({:?}) --- managed to MARK \ - dependency {:?} as green", - dep_node, dep_dep_node - ); - current_deps.push(node_index); - continue; - } - } else { - match dep_dep_node.kind { - DepKind::Hir | DepKind::HirBody | DepKind::CrateMetadata => { - if let Some(def_id) = dep_dep_node.extract_def_id(tcx) { - if def_id_corresponds_to_hir_dep_node(tcx, def_id) { - // The `DefPath` has corresponding node, - // and that node should have been marked - // either red or green in `data.colors`. - bug!( - "DepNode {:?} should have been \ - pre-marked as red or green but wasn't.", - dep_dep_node - ); - } else { - // This `DefPath` does not have a - // corresponding `DepNode` (e.g. a - // struct field), and the ` DefPath` - // collided with the `DefPath` of a - // proper item that existed in the - // previous compilation session. - // - // Since the given `DefPath` does not - // denote the item that previously - // existed, we just fail to mark green. - return None; - } - } else { - // If the node does not exist anymore, we - // just fail to mark green. - return None; - } - } - _ => { - // For other kinds of nodes it's OK to be - // forced. - } - } - } - - // We failed to mark it green, so we try to force the query. - debug!( - "try_mark_previous_green({:?}) --- trying to force \ - dependency {:?}", - dep_node, dep_dep_node - ); - if crate::ty::query::force_from_dep_node(tcx, dep_dep_node) { - let dep_dep_node_color = data.colors.get(dep_dep_node_index); - - match dep_dep_node_color { - Some(DepNodeColor::Green(node_index)) => { - debug!( - "try_mark_previous_green({:?}) --- managed to \ - FORCE dependency {:?} to green", - dep_node, dep_dep_node - ); - current_deps.push(node_index); - } - Some(DepNodeColor::Red) => { - debug!( - "try_mark_previous_green({:?}) - END - \ - dependency {:?} was red after forcing", - dep_node, dep_dep_node - ); - return None; - } - None => { - if !tcx.sess.has_errors_or_delayed_span_bugs() { - bug!( - "try_mark_previous_green() - Forcing the DepNode \ - should have set its color" - ) - } else { - // If the query we just forced has resulted in - // some kind of compilation error, we cannot rely on - // the dep-node color having been properly updated. - // This means that the query system has reached an - // invalid state. We let the compiler continue (by - // returning `None`) so it can emit error messages - // and wind down, but rely on the fact that this - // invalid state will not be persisted to the - // incremental compilation cache because of - // compilation errors being present. - debug!( - "try_mark_previous_green({:?}) - END - \ - dependency {:?} resulted in compilation error", - dep_node, dep_dep_node - ); - return None; - } - } - } - } else { - // The DepNode could not be forced. - debug!( - "try_mark_previous_green({:?}) - END - dependency {:?} \ - could not be forced", - dep_node, dep_dep_node - ); - return None; - } - } - } - } - - // If we got here without hitting a `return` that means that all - // dependencies of this DepNode could be marked as green. Therefore we - // can also mark this DepNode as green. - - // There may be multiple threads trying to mark the same dep node green concurrently - - let dep_node_index = { - // Copy the fingerprint from the previous graph, - // so we don't have to recompute it - let fingerprint = data.previous.fingerprint_by_index(prev_dep_node_index); - - // We allocating an entry for the node in the current dependency graph and - // adding all the appropriate edges imported from the previous graph - data.current.intern_node(*dep_node, current_deps, fingerprint) - }; - - // ... emitting any stored diagnostic ... - - // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere - // Maybe store a list on disk and encode this fact in the DepNodeState - let diagnostics = tcx.queries.on_disk_cache.load_diagnostics(tcx, prev_dep_node_index); - - #[cfg(not(parallel_compiler))] - debug_assert!( - data.colors.get(prev_dep_node_index).is_none(), - "DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \ - insertion for {:?}", - dep_node - ); - - if unlikely!(diagnostics.len() > 0) { - self.emit_diagnostics(tcx, data, dep_node_index, prev_dep_node_index, diagnostics); - } - - // ... and finally storing a "Green" entry in the color map. - // Multiple threads can all write the same color here - data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); - - debug!("try_mark_previous_green({:?}) - END - successfully marked as green", dep_node); - Some(dep_node_index) - } - - /// Atomically emits some loaded diagnostics. - /// This may be called concurrently on multiple threads for the same dep node. - #[cold] - #[inline(never)] - fn emit_diagnostics<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - data: &DepGraphData, - dep_node_index: DepNodeIndex, - prev_dep_node_index: SerializedDepNodeIndex, - diagnostics: Vec<Diagnostic>, - ) { - let mut emitting = data.emitting_diagnostics.lock(); - - if data.colors.get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index)) { - // The node is already green so diagnostics must have been emitted already - return; - } - - if emitting.insert(dep_node_index) { - // We were the first to insert the node in the set so this thread - // must emit the diagnostics and signal other potentially waiting - // threads after. - mem::drop(emitting); - - // Promote the previous diagnostics to the current session. - tcx.queries.on_disk_cache.store_diagnostics(dep_node_index, diagnostics.clone().into()); - - let handle = tcx.sess.diagnostic(); - - for diagnostic in diagnostics { - handle.emit_diagnostic(&diagnostic); - } - - // Mark the node as green now that diagnostics are emitted - data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); - - // Remove the node from the set - data.emitting_diagnostics.lock().remove(&dep_node_index); - - // Wake up waiters - data.emitting_diagnostics_cond_var.notify_all(); - } else { - // We must wait for the other thread to finish emitting the diagnostic - - loop { - data.emitting_diagnostics_cond_var.wait(&mut emitting); - if data.colors.get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index)) - { - break; - } - } - } - } - - // Returns true if the given node has been marked as green during the - // current compilation session. Used in various assertions - pub fn is_green(&self, dep_node: &DepNode) -> bool { - self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false) - } - - // This method loads all on-disk cacheable query results into memory, so - // they can be written out to the new cache file again. Most query results - // will already be in memory but in the case where we marked something as - // green but then did not need the value, that value will never have been - // loaded from disk. - // - // This method will only load queries that will end up in the disk cache. - // Other queries will not be executed. - pub fn exec_cache_promotions(&self, tcx: TyCtxt<'_>) { - let _prof_timer = tcx.prof.generic_activity("incr_comp_query_cache_promotion"); - - let data = self.data.as_ref().unwrap(); - for prev_index in data.colors.values.indices() { - match data.colors.get(prev_index) { - Some(DepNodeColor::Green(_)) => { - let dep_node = data.previous.index_to_node(prev_index); - dep_node.try_load_from_on_disk_cache(tcx); - } - None | Some(DepNodeColor::Red) => { - // We can skip red nodes because a node can only be marked - // as red if the query result was recomputed and thus is - // already in memory. - } - } - } - } - - fn next_virtual_depnode_index(&self) -> DepNodeIndex { - let index = self.virtual_dep_node_index.fetch_add(1, Relaxed); - DepNodeIndex::from_u32(index) - } -} - -fn def_id_corresponds_to_hir_dep_node(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - def_id.index == hir_id.owner -} - -/// A "work product" is an intermediate result that we save into the -/// incremental directory for later re-use. The primary example are -/// the object files that we save for each partition at code -/// generation time. -/// -/// Each work product is associated with a dep-node, representing the -/// process that produced the work-product. If that dep-node is found -/// to be dirty when we load up, then we will delete the work-product -/// at load time. If the work-product is found to be clean, then we -/// will keep a record in the `previous_work_products` list. -/// -/// In addition, work products have an associated hash. This hash is -/// an extra hash that can be used to decide if the work-product from -/// a previous compilation can be re-used (in addition to the dirty -/// edges check). -/// -/// As the primary example, consider the object files we generate for -/// each partition. In the first run, we create partitions based on -/// the symbols that need to be compiled. For each partition P, we -/// hash the symbols in P and create a `WorkProduct` record associated -/// with `DepNode::CodegenUnit(P)`; the hash is the set of symbols -/// in P. -/// -/// The next time we compile, if the `DepNode::CodegenUnit(P)` is -/// judged to be clean (which means none of the things we read to -/// generate the partition were found to be dirty), it will be loaded -/// into previous work products. We will then regenerate the set of -/// symbols in the partition P and hash them (note that new symbols -/// may be added -- for example, new monomorphizations -- even if -/// nothing in P changed!). We will compare that hash against the -/// previous hash. If it matches up, we can reuse the object file. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct WorkProduct { - pub cgu_name: String, - /// Saved files associated with this CGU. - pub saved_files: Vec<(WorkProductFileKind, String)>, -} - -#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable, PartialEq)] -pub enum WorkProductFileKind { - Object, - Bytecode, - BytecodeCompressed, -} - -#[derive(Clone)] -struct DepNodeData { - node: DepNode, - edges: SmallVec<[DepNodeIndex; 8]>, - fingerprint: Fingerprint, -} - -/// `CurrentDepGraph` stores the dependency graph for the current session. -/// It will be populated as we run queries or tasks. -/// -/// The nodes in it are identified by an index (`DepNodeIndex`). -/// The data for each node is stored in its `DepNodeData`, found in the `data` field. -/// -/// We never remove nodes from the graph: they are only added. -/// -/// This struct uses two locks internally. The `data` and `node_to_node_index` fields are -/// locked separately. Operations that take a `DepNodeIndex` typically just access -/// the data field. -/// -/// The only operation that must manipulate both locks is adding new nodes, in which case -/// we first acquire the `node_to_node_index` lock and then, once a new node is to be inserted, -/// acquire the lock on `data.` -pub(super) struct CurrentDepGraph { - data: Lock<IndexVec<DepNodeIndex, DepNodeData>>, - node_to_node_index: Sharded<FxHashMap<DepNode, DepNodeIndex>>, - - /// Used to trap when a specific edge is added to the graph. - /// This is used for debug purposes and is only active with `debug_assertions`. - #[allow(dead_code)] - forbidden_edge: Option<EdgeFilter>, - - /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of - /// their edges. This has the beneficial side-effect that multiple anonymous - /// nodes can be coalesced into one without changing the semantics of the - /// dependency graph. However, the merging of nodes can lead to a subtle - /// problem during red-green marking: The color of an anonymous node from - /// the current session might "shadow" the color of the node with the same - /// ID from the previous session. In order to side-step this problem, we make - /// sure that anonymous `NodeId`s allocated in different sessions don't overlap. - /// This is implemented by mixing a session-key into the ID fingerprint of - /// each anon node. The session-key is just a random number generated when - /// the `DepGraph` is created. - anon_id_seed: Fingerprint, - - /// These are simple counters that are for profiling and - /// debugging and only active with `debug_assertions`. - total_read_count: AtomicU64, - total_duplicate_read_count: AtomicU64, -} - -impl CurrentDepGraph { - fn new(prev_graph_node_count: usize) -> CurrentDepGraph { - use std::time::{SystemTime, UNIX_EPOCH}; - - let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); - let nanos = duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64; - let mut stable_hasher = StableHasher::new(); - nanos.hash(&mut stable_hasher); - - let forbidden_edge = if cfg!(debug_assertions) { - match env::var("RUST_FORBID_DEP_GRAPH_EDGE") { - Ok(s) => match EdgeFilter::new(&s) { - Ok(f) => Some(f), - Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err), - }, - Err(_) => None, - } - } else { - None - }; - - // Pre-allocate the dep node structures. We over-allocate a little so - // that we hopefully don't have to re-allocate during this compilation - // session. The over-allocation is 2% plus a small constant to account - // for the fact that in very small crates 2% might not be enough. - let new_node_count_estimate = (prev_graph_node_count * 102) / 100 + 200; - - CurrentDepGraph { - data: Lock::new(IndexVec::with_capacity(new_node_count_estimate)), - node_to_node_index: Sharded::new(|| { - FxHashMap::with_capacity_and_hasher( - new_node_count_estimate / sharded::SHARDS, - Default::default(), - ) - }), - anon_id_seed: stable_hasher.finish(), - forbidden_edge, - total_read_count: AtomicU64::new(0), - total_duplicate_read_count: AtomicU64::new(0), - } - } - - fn complete_task( - &self, - node: DepNode, - task_deps: TaskDeps, - fingerprint: Fingerprint, - ) -> DepNodeIndex { - self.alloc_node(node, task_deps.reads, fingerprint) - } - - fn complete_anon_task(&self, kind: DepKind, task_deps: TaskDeps) -> DepNodeIndex { - debug_assert!(!kind.is_eval_always()); - - let mut hasher = StableHasher::new(); - - // The dep node indices are hashed here instead of hashing the dep nodes of the - // dependencies. These indices may refer to different nodes per session, but this isn't - // a problem here because we that ensure the final dep node hash is per session only by - // combining it with the per session random number `anon_id_seed`. This hash only need - // to map the dependencies to a single value on a per session basis. - task_deps.reads.hash(&mut hasher); - - let target_dep_node = DepNode { - kind, - - // Fingerprint::combine() is faster than sending Fingerprint - // through the StableHasher (at least as long as StableHasher - // is so slow). - hash: self.anon_id_seed.combine(hasher.finish()), - }; - - self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO) - } - - fn alloc_node( - &self, - dep_node: DepNode, - edges: SmallVec<[DepNodeIndex; 8]>, - fingerprint: Fingerprint, - ) -> DepNodeIndex { - debug_assert!( - !self.node_to_node_index.get_shard_by_value(&dep_node).lock().contains_key(&dep_node) - ); - self.intern_node(dep_node, edges, fingerprint) - } - - fn intern_node( - &self, - dep_node: DepNode, - edges: SmallVec<[DepNodeIndex; 8]>, - fingerprint: Fingerprint, - ) -> DepNodeIndex { - match self.node_to_node_index.get_shard_by_value(&dep_node).lock().entry(dep_node) { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let mut data = self.data.lock(); - let dep_node_index = DepNodeIndex::new(data.len()); - data.push(DepNodeData { node: dep_node, edges, fingerprint }); - entry.insert(dep_node_index); - dep_node_index - } - } - } -} - -impl DepGraphData { - #[inline(never)] - fn read_index(&self, source: DepNodeIndex) { - ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; - if let Some(task_deps) = icx.task_deps { - let mut task_deps = task_deps.lock(); - if cfg!(debug_assertions) { - self.current.total_read_count.fetch_add(1, Relaxed); - } - if task_deps.read_set.insert(source) { - task_deps.reads.push(source); - - #[cfg(debug_assertions)] - { - if let Some(target) = task_deps.node { - let data = self.current.data.lock(); - if let Some(ref forbidden_edge) = self.current.forbidden_edge { - let source = data[source].node; - if forbidden_edge.test(&source, &target) { - bug!("forbidden edge {:?} -> {:?} created", source, target) - } - } - } - } - } else if cfg!(debug_assertions) { - self.current.total_duplicate_read_count.fetch_add(1, Relaxed); - } - } - }) - } -} - -pub struct TaskDeps { - #[cfg(debug_assertions)] - node: Option<DepNode>, - reads: SmallVec<[DepNodeIndex; 8]>, - read_set: FxHashSet<DepNodeIndex>, -} - -// A data structure that stores Option<DepNodeColor> values as a contiguous -// array, using one u32 per entry. -struct DepNodeColorMap { - values: IndexVec<SerializedDepNodeIndex, AtomicU32>, -} - -const COMPRESSED_NONE: u32 = 0; -const COMPRESSED_RED: u32 = 1; -const COMPRESSED_FIRST_GREEN: u32 = 2; - -impl DepNodeColorMap { - fn new(size: usize) -> DepNodeColorMap { - DepNodeColorMap { values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect() } - } - - fn get(&self, index: SerializedDepNodeIndex) -> Option<DepNodeColor> { - match self.values[index].load(Ordering::Acquire) { - COMPRESSED_NONE => None, - COMPRESSED_RED => Some(DepNodeColor::Red), - value => { - Some(DepNodeColor::Green(DepNodeIndex::from_u32(value - COMPRESSED_FIRST_GREEN))) - } - } - } - - fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) { - self.values[index].store( - match color { - DepNodeColor::Red => COMPRESSED_RED, - DepNodeColor::Green(index) => index.as_u32() + COMPRESSED_FIRST_GREEN, - }, - Ordering::Release, - ) - } -} diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs deleted file mode 100644 index eb377d20f59..00000000000 --- a/src/librustc/dep_graph/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub mod debug; -mod dep_node; -mod graph; -mod prev; -mod query; -mod safe; -mod serialized; - -pub use self::dep_node::{label_strs, DepConstructor, DepKind, DepNode, RecoverKey, WorkProductId}; -pub use self::graph::WorkProductFileKind; -pub use self::graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct}; -pub use self::prev::PreviousDepGraph; -pub use self::query::DepGraphQuery; -pub use self::safe::AssertDepGraphSafe; -pub use self::safe::DepGraphSafe; -pub use self::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; diff --git a/src/librustc/dep_graph/prev.rs b/src/librustc/dep_graph/prev.rs deleted file mode 100644 index fbc8f7bc997..00000000000 --- a/src/librustc/dep_graph/prev.rs +++ /dev/null @@ -1,55 +0,0 @@ -use super::dep_node::DepNode; -use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; -use crate::ich::Fingerprint; -use rustc_data_structures::fx::FxHashMap; - -#[derive(Debug, RustcEncodable, RustcDecodable, Default)] -pub struct PreviousDepGraph { - data: SerializedDepGraph, - index: FxHashMap<DepNode, SerializedDepNodeIndex>, -} - -impl PreviousDepGraph { - pub fn new(data: SerializedDepGraph) -> PreviousDepGraph { - let index: FxHashMap<_, _> = - data.nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect(); - PreviousDepGraph { data, index } - } - - #[inline] - pub fn edge_targets_from( - &self, - dep_node_index: SerializedDepNodeIndex, - ) -> &[SerializedDepNodeIndex] { - self.data.edge_targets_from(dep_node_index) - } - - #[inline] - pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { - self.data.nodes[dep_node_index] - } - - #[inline] - pub fn node_to_index(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { - self.index[dep_node] - } - - #[inline] - pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> { - self.index.get(dep_node).cloned() - } - - #[inline] - pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> { - self.index.get(dep_node).map(|&node_index| self.data.fingerprints[node_index]) - } - - #[inline] - pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint { - self.data.fingerprints[dep_node_index] - } - - pub fn node_count(&self) -> usize { - self.index.len() - } -} diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs deleted file mode 100644 index c71c11ed0eb..00000000000 --- a/src/librustc/dep_graph/query.rs +++ /dev/null @@ -1,74 +0,0 @@ -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::implementation::{ - Direction, Graph, NodeIndex, INCOMING, OUTGOING, -}; - -use super::DepNode; - -pub struct DepGraphQuery { - pub graph: Graph<DepNode, ()>, - pub indices: FxHashMap<DepNode, NodeIndex>, -} - -impl DepGraphQuery { - pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery { - let mut graph = Graph::with_capacity(nodes.len(), edges.len()); - let mut indices = FxHashMap::default(); - for node in nodes { - indices.insert(node.clone(), graph.add_node(node.clone())); - } - - for &(ref source, ref target) in edges { - let source = indices[source]; - let target = indices[target]; - graph.add_edge(source, target, ()); - } - - DepGraphQuery { graph, indices } - } - - pub fn contains_node(&self, node: &DepNode) -> bool { - self.indices.contains_key(&node) - } - - pub fn nodes(&self) -> Vec<&DepNode> { - self.graph.all_nodes().iter().map(|n| &n.data).collect() - } - - pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { - self.graph - .all_edges() - .iter() - .map(|edge| (edge.source(), edge.target())) - .map(|(s, t)| (self.graph.node_data(s), self.graph.node_data(t))) - .collect() - } - - fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { - if let Some(&index) = self.indices.get(node) { - self.graph.depth_traverse(index, direction).map(|s| self.graph.node_data(s)).collect() - } else { - vec![] - } - } - - /// All nodes reachable from `node`. In other words, things that - /// will have to be recomputed if `node` changes. - pub fn transitive_successors(&self, node: &DepNode) -> Vec<&DepNode> { - self.reachable_nodes(node, OUTGOING) - } - - /// All nodes that can reach `node`. - pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { - self.reachable_nodes(node, INCOMING) - } - - /// Just the outgoing edges from `node`. - pub fn immediate_successors(&self, node: &DepNode) -> Vec<&DepNode> { - if let Some(&index) = self.indices.get(&node) { - self.graph.successor_nodes(index).map(|s| self.graph.node_data(s)).collect() - } else { - vec![] - } - } -} diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs deleted file mode 100644 index 23aef0c4298..00000000000 --- a/src/librustc/dep_graph/safe.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! The `DepGraphSafe` trait - -use crate::ty::TyCtxt; - -use rustc_hir::def_id::DefId; -use rustc_hir::BodyId; -use syntax::ast::NodeId; - -/// The `DepGraphSafe` trait is used to specify what kinds of values -/// are safe to "leak" into a task. The idea is that this should be -/// only be implemented for things like the tcx as well as various id -/// types, which will create reads in the dep-graph whenever the trait -/// loads anything that might depend on the input program. -pub trait DepGraphSafe {} - -/// A `BodyId` on its own doesn't give access to any particular state. -/// You must fetch the state from the various maps or generate -/// on-demand queries, all of which create reads. -impl DepGraphSafe for BodyId {} - -/// A `NodeId` on its own doesn't give access to any particular state. -/// You must fetch the state from the various maps or generate -/// on-demand queries, all of which create reads. -impl DepGraphSafe for NodeId {} - -/// A `DefId` on its own doesn't give access to any particular state. -/// You must fetch the state from the various maps or generate -/// on-demand queries, all of which create reads. -impl DepGraphSafe for DefId {} - -/// The type context itself can be used to access all kinds of tracked -/// state, but those accesses should always generate read events. -impl<'tcx> DepGraphSafe for TyCtxt<'tcx> {} - -/// Tuples make it easy to build up state. -impl<A, B> DepGraphSafe for (A, B) -where - A: DepGraphSafe, - B: DepGraphSafe, -{ -} - -/// Shared ref to dep-graph-safe stuff should still be dep-graph-safe. -impl<'a, A> DepGraphSafe for &'a A where A: DepGraphSafe {} - -/// Mut ref to dep-graph-safe stuff should still be dep-graph-safe. -impl<'a, A> DepGraphSafe for &'a mut A where A: DepGraphSafe {} - -/// No data here! :) -impl DepGraphSafe for () {} - -/// A convenient override that lets you pass arbitrary state into a -/// task. Every use should be accompanied by a comment explaining why -/// it makes sense (or how it could be refactored away in the future). -pub struct AssertDepGraphSafe<T>(pub T); - -impl<T> DepGraphSafe for AssertDepGraphSafe<T> {} diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc/dep_graph/serialized.rs deleted file mode 100644 index 45ef52dbf39..00000000000 --- a/src/librustc/dep_graph/serialized.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! The data that we will serialize and deserialize. - -use crate::dep_graph::DepNode; -use crate::ich::Fingerprint; -use rustc_index::vec::IndexVec; - -rustc_index::newtype_index! { - pub struct SerializedDepNodeIndex { .. } -} - -/// Data for use when recompiling the **current crate**. -#[derive(Debug, RustcEncodable, RustcDecodable, Default)] -pub struct SerializedDepGraph { - /// The set of all DepNodes in the graph - pub nodes: IndexVec<SerializedDepNodeIndex, DepNode>, - /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to - /// the DepNode at the same index in the nodes vector. - pub fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>, - /// For each DepNode, stores the list of edges originating from that - /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data, - /// which holds the actual DepNodeIndices of the target nodes. - pub edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>, - /// A flattened list of all edge targets in the graph. Edge sources are - /// implicit in edge_list_indices. - pub edge_list_data: Vec<SerializedDepNodeIndex>, -} - -impl SerializedDepGraph { - #[inline] - pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] { - let targets = self.edge_list_indices[source]; - &self.edge_list_data[targets.0 as usize..targets.1 as usize] - } -} diff --git a/src/librustc/hir/exports.rs b/src/librustc/hir/exports.rs deleted file mode 100644 index db020e39e8e..00000000000 --- a/src/librustc/hir/exports.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::ty; - -use rustc_hir::def::Res; -use rustc_hir::def_id::DefIdMap; -use rustc_macros::HashStable; -use rustc_span::Span; -use syntax::ast; - -use std::fmt::Debug; - -/// This is the replacement export map. It maps a module to all of the exports -/// within. -pub type ExportMap<Id> = DefIdMap<Vec<Export<Id>>>; - -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct Export<Id> { - /// The name of the target. - pub ident: ast::Ident, - /// The resolution of the target. - pub res: Res<Id>, - /// The span of the target. - pub span: Span, - /// The visibility of the export. - /// We include non-`pub` exports for hygienic macros that get used from extern crates. - pub vis: ty::Visibility, -} - -impl<Id> Export<Id> { - pub fn map_id<R>(self, map: impl FnMut(Id) -> R) -> Export<R> { - Export { ident: self.ident, res: self.res.map_id(map), span: self.span, vis: self.vis } - } -} diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs deleted file mode 100644 index 016fc939a7a..00000000000 --- a/src/librustc/hir/map/blocks.rs +++ /dev/null @@ -1,262 +0,0 @@ -//! This module provides a simplified abstraction for working with -//! code blocks identified by their integer `NodeId`. In particular, -//! it captures a common set of attributes that all "function-like -//! things" (represented by `FnLike` instances) share. For example, -//! all `FnLike` instances have a type signature (be it explicit or -//! inferred). And all `FnLike` instances have a body, i.e., the code -//! that is run when the function-like thing it represents is invoked. -//! -//! With the above abstraction in place, one can treat the program -//! text as a collection of blocks of code (and most such blocks are -//! nested within a uniquely determined `FnLike`), and users can ask -//! for the `Code` associated with a particular NodeId. - -use crate::hir::map::Map; -use rustc_hir as hir; -use rustc_hir::intravisit::FnKind; -use rustc_hir::{Expr, FnDecl, Node}; -use rustc_span::Span; -use syntax::ast::{Attribute, Ident}; - -/// An FnLikeNode is a Node that is like a fn, in that it has a decl -/// and a body (as well as a NodeId, a span, etc). -/// -/// More specifically, it is one of either: -/// -/// - A function item, -/// - A closure expr (i.e., an ExprKind::Closure), or -/// - The default implementation for a trait method. -/// -/// To construct one, use the `Code::from_node` function. -#[derive(Copy, Clone, Debug)] -pub struct FnLikeNode<'a> { - node: Node<'a>, -} - -/// MaybeFnLike wraps a method that indicates if an object -/// corresponds to some FnLikeNode. -trait MaybeFnLike { - fn is_fn_like(&self) -> bool; -} - -impl MaybeFnLike for hir::Item<'_> { - fn is_fn_like(&self) -> bool { - match self.kind { - hir::ItemKind::Fn(..) => true, - _ => false, - } - } -} - -impl MaybeFnLike for hir::ImplItem<'_> { - fn is_fn_like(&self) -> bool { - match self.kind { - hir::ImplItemKind::Method(..) => true, - _ => false, - } - } -} - -impl MaybeFnLike for hir::TraitItem<'_> { - fn is_fn_like(&self) -> bool { - match self.kind { - hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => true, - _ => false, - } - } -} - -impl MaybeFnLike for hir::Expr<'_> { - fn is_fn_like(&self) -> bool { - match self.kind { - hir::ExprKind::Closure(..) => true, - _ => false, - } - } -} - -/// Carries either an FnLikeNode or a Expr, as these are the two -/// constructs that correspond to "code" (as in, something from which -/// we can construct a control-flow graph). -#[derive(Copy, Clone)] -pub enum Code<'a> { - FnLike(FnLikeNode<'a>), - Expr(&'a Expr<'a>), -} - -impl<'a> Code<'a> { - pub fn id(&self) -> hir::HirId { - match *self { - Code::FnLike(node) => node.id(), - Code::Expr(block) => block.hir_id, - } - } - - /// Attempts to construct a Code from presumed FnLike or Expr node input. - pub fn from_node(map: &Map<'a>, id: hir::HirId) -> Option<Code<'a>> { - match map.get(id) { - Node::Block(_) => { - // Use the parent, hopefully an expression node. - Code::from_node(map, map.get_parent_node(id)) - } - Node::Expr(expr) => Some(Code::Expr(expr)), - node => FnLikeNode::from_node(node).map(Code::FnLike), - } - } -} - -/// These are all the components one can extract from a fn item for -/// use when implementing FnLikeNode operations. -struct ItemFnParts<'a> { - ident: Ident, - decl: &'a hir::FnDecl<'a>, - header: hir::FnHeader, - vis: &'a hir::Visibility<'a>, - generics: &'a hir::Generics<'a>, - body: hir::BodyId, - id: hir::HirId, - span: Span, - attrs: &'a [Attribute], -} - -/// These are all the components one can extract from a closure expr -/// for use when implementing FnLikeNode operations. -struct ClosureParts<'a> { - decl: &'a FnDecl<'a>, - body: hir::BodyId, - id: hir::HirId, - span: Span, - attrs: &'a [Attribute], -} - -impl<'a> ClosureParts<'a> { - fn new( - d: &'a FnDecl<'a>, - b: hir::BodyId, - id: hir::HirId, - s: Span, - attrs: &'a [Attribute], - ) -> Self { - ClosureParts { decl: d, body: b, id, span: s, attrs } - } -} - -impl<'a> FnLikeNode<'a> { - /// Attempts to construct a FnLikeNode from presumed FnLike node input. - pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> { - let fn_like = match node { - Node::Item(item) => item.is_fn_like(), - Node::TraitItem(tm) => tm.is_fn_like(), - Node::ImplItem(it) => it.is_fn_like(), - Node::Expr(e) => e.is_fn_like(), - _ => false, - }; - fn_like.then_some(FnLikeNode { node }) - } - - pub fn body(self) -> hir::BodyId { - self.handle( - |i: ItemFnParts<'a>| i.body, - |_, _, _: &'a hir::FnSig<'a>, _, body: hir::BodyId, _, _| body, - |c: ClosureParts<'a>| c.body, - ) - } - - pub fn decl(self) -> &'a FnDecl<'a> { - self.handle( - |i: ItemFnParts<'a>| &*i.decl, - |_, _, sig: &'a hir::FnSig<'a>, _, _, _, _| &sig.decl, - |c: ClosureParts<'a>| c.decl, - ) - } - - pub fn span(self) -> Span { - self.handle( - |i: ItemFnParts<'_>| i.span, - |_, _, _: &'a hir::FnSig<'a>, _, _, span, _| span, - |c: ClosureParts<'_>| c.span, - ) - } - - pub fn id(self) -> hir::HirId { - self.handle( - |i: ItemFnParts<'_>| i.id, - |id, _, _: &'a hir::FnSig<'a>, _, _, _, _| id, - |c: ClosureParts<'_>| c.id, - ) - } - - pub fn constness(self) -> hir::Constness { - self.kind().header().map_or(hir::Constness::NotConst, |header| header.constness) - } - - pub fn asyncness(self) -> hir::IsAsync { - self.kind().header().map_or(hir::IsAsync::NotAsync, |header| header.asyncness) - } - - pub fn unsafety(self) -> hir::Unsafety { - self.kind().header().map_or(hir::Unsafety::Normal, |header| header.unsafety) - } - - pub fn kind(self) -> FnKind<'a> { - let item = |p: ItemFnParts<'a>| -> FnKind<'a> { - FnKind::ItemFn(p.ident, p.generics, p.header, p.vis, p.attrs) - }; - let closure = |c: ClosureParts<'a>| FnKind::Closure(c.attrs); - let method = |_, ident: Ident, sig: &'a hir::FnSig<'a>, vis, _, _, attrs| { - FnKind::Method(ident, sig, vis, attrs) - }; - self.handle(item, method, closure) - } - - fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A - where - I: FnOnce(ItemFnParts<'a>) -> A, - M: FnOnce( - hir::HirId, - Ident, - &'a hir::FnSig<'a>, - Option<&'a hir::Visibility<'a>>, - hir::BodyId, - Span, - &'a [Attribute], - ) -> A, - C: FnOnce(ClosureParts<'a>) -> A, - { - match self.node { - Node::Item(i) => match i.kind { - hir::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts { - id: i.hir_id, - ident: i.ident, - decl: &sig.decl, - body: block, - vis: &i.vis, - span: i.span, - attrs: &i.attrs, - header: sig.header, - generics, - }), - _ => bug!("item FnLikeNode that is not fn-like"), - }, - Node::TraitItem(ti) => match ti.kind { - hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => { - method(ti.hir_id, ti.ident, sig, None, body, ti.span, &ti.attrs) - } - _ => bug!("trait method FnLikeNode that is not fn-like"), - }, - Node::ImplItem(ii) => match ii.kind { - hir::ImplItemKind::Method(ref sig, body) => { - method(ii.hir_id, ii.ident, sig, Some(&ii.vis), body, ii.span, &ii.attrs) - } - _ => bug!("impl method FnLikeNode that is not fn-like"), - }, - Node::Expr(e) => match e.kind { - hir::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => { - closure(ClosureParts::new(&decl, block, e.hir_id, e.span, &e.attrs)) - } - _ => bug!("expr FnLikeNode that is not fn-like"), - }, - _ => bug!("other FnLikeNode that is not fn-like"), - } - } -} diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs deleted file mode 100644 index bf1fc09649a..00000000000 --- a/src/librustc/hir/map/collector.rs +++ /dev/null @@ -1,603 +0,0 @@ -use crate::dep_graph::{DepGraph, DepKind, DepNode, DepNodeIndex}; -use crate::hir::map::definitions::{self, DefPathHash}; -use crate::hir::map::{Entry, HirEntryMap, Map}; -use crate::ich::StableHashingContext; -use crate::middle::cstore::CrateStore; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::svh::Svh; -use rustc_hir as hir; -use rustc_hir::def_id::CRATE_DEF_INDEX; -use rustc_hir::def_id::{CrateNum, DefIndex, LOCAL_CRATE}; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::*; -use rustc_index::vec::IndexVec; -use rustc_session::{CrateDisambiguator, Session}; -use rustc_span::source_map::SourceMap; -use rustc_span::{Span, Symbol, DUMMY_SP}; -use syntax::ast::NodeId; - -use std::iter::repeat; - -/// A visitor that walks over the HIR and collects `Node`s into a HIR map. -pub(super) struct NodeCollector<'a, 'hir> { - /// The crate - krate: &'hir Crate<'hir>, - - /// Source map - source_map: &'a SourceMap, - - /// The node map - map: HirEntryMap<'hir>, - /// The parent of this node - parent_node: hir::HirId, - - // These fields keep track of the currently relevant DepNodes during - // the visitor's traversal. - current_dep_node_owner: DefIndex, - current_signature_dep_index: DepNodeIndex, - current_full_dep_index: DepNodeIndex, - currently_in_body: bool, - - dep_graph: &'a DepGraph, - definitions: &'a definitions::Definitions, - hir_to_node_id: &'a FxHashMap<HirId, NodeId>, - - hcx: StableHashingContext<'a>, - - // We are collecting `DepNode::HirBody` hashes here so we can compute the - // crate hash from then later on. - hir_body_nodes: Vec<(DefPathHash, Fingerprint)>, -} - -fn input_dep_node_and_hash( - dep_graph: &DepGraph, - hcx: &mut StableHashingContext<'_>, - dep_node: DepNode, - input: impl for<'a> HashStable<StableHashingContext<'a>>, -) -> (DepNodeIndex, Fingerprint) { - let dep_node_index = dep_graph.input_task(dep_node, &mut *hcx, &input).1; - - let hash = if dep_graph.is_fully_enabled() { - dep_graph.fingerprint_of(dep_node_index) - } else { - let mut stable_hasher = StableHasher::new(); - input.hash_stable(hcx, &mut stable_hasher); - stable_hasher.finish() - }; - - (dep_node_index, hash) -} - -fn alloc_hir_dep_nodes( - dep_graph: &DepGraph, - hcx: &mut StableHashingContext<'_>, - def_path_hash: DefPathHash, - item_like: impl for<'a> HashStable<StableHashingContext<'a>>, - hir_body_nodes: &mut Vec<(DefPathHash, Fingerprint)>, -) -> (DepNodeIndex, DepNodeIndex) { - let sig = dep_graph - .input_task( - def_path_hash.to_dep_node(DepKind::Hir), - &mut *hcx, - HirItemLike { item_like: &item_like, hash_bodies: false }, - ) - .1; - let (full, hash) = input_dep_node_and_hash( - dep_graph, - hcx, - def_path_hash.to_dep_node(DepKind::HirBody), - HirItemLike { item_like: &item_like, hash_bodies: true }, - ); - hir_body_nodes.push((def_path_hash, hash)); - (sig, full) -} - -fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> { - let mut upstream_crates: Vec<_> = cstore - .crates_untracked() - .iter() - .map(|&cnum| { - let name = cstore.crate_name_untracked(cnum); - let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint(); - let hash = cstore.crate_hash_untracked(cnum); - (name, disambiguator, hash) - }) - .collect(); - upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis)); - upstream_crates -} - -impl<'a, 'hir> NodeCollector<'a, 'hir> { - pub(super) fn root( - sess: &'a Session, - krate: &'hir Crate<'hir>, - dep_graph: &'a DepGraph, - definitions: &'a definitions::Definitions, - hir_to_node_id: &'a FxHashMap<HirId, NodeId>, - mut hcx: StableHashingContext<'a>, - ) -> NodeCollector<'a, 'hir> { - let root_mod_def_path_hash = definitions.def_path_hash(CRATE_DEF_INDEX); - - let mut hir_body_nodes = Vec::new(); - - // Allocate `DepNode`s for the root module. - let (root_mod_sig_dep_index, root_mod_full_dep_index) = { - let Crate { - ref module, - // Crate attributes are not copied over to the root `Mod`, so hash - // them explicitly here. - ref attrs, - span, - // These fields are handled separately: - exported_macros: _, - non_exported_macro_attrs: _, - items: _, - trait_items: _, - impl_items: _, - bodies: _, - trait_impls: _, - body_ids: _, - modules: _, - proc_macros: _, - } = *krate; - - alloc_hir_dep_nodes( - dep_graph, - &mut hcx, - root_mod_def_path_hash, - (module, attrs, span), - &mut hir_body_nodes, - ) - }; - - { - dep_graph.input_task( - DepNode::new_no_params(DepKind::AllLocalTraitImpls), - &mut hcx, - &krate.trait_impls, - ); - } - - let mut collector = NodeCollector { - krate, - source_map: sess.source_map(), - map: IndexVec::from_elem_n(IndexVec::new(), definitions.def_index_count()), - parent_node: hir::CRATE_HIR_ID, - current_signature_dep_index: root_mod_sig_dep_index, - current_full_dep_index: root_mod_full_dep_index, - current_dep_node_owner: CRATE_DEF_INDEX, - currently_in_body: false, - dep_graph, - definitions, - hir_to_node_id, - hcx, - hir_body_nodes, - }; - collector.insert_entry( - hir::CRATE_HIR_ID, - Entry { - parent: hir::CRATE_HIR_ID, - dep_node: root_mod_sig_dep_index, - node: Node::Crate, - }, - ); - - collector - } - - pub(super) fn finalize_and_compute_crate_hash( - mut self, - crate_disambiguator: CrateDisambiguator, - cstore: &dyn CrateStore, - commandline_args_hash: u64, - ) -> (HirEntryMap<'hir>, Svh) { - self.hir_body_nodes.sort_unstable_by_key(|bn| bn.0); - - let node_hashes = self.hir_body_nodes.iter().fold( - Fingerprint::ZERO, - |combined_fingerprint, &(def_path_hash, fingerprint)| { - combined_fingerprint.combine(def_path_hash.0.combine(fingerprint)) - }, - ); - - let upstream_crates = upstream_crates(cstore); - - // We hash the final, remapped names of all local source files so we - // don't have to include the path prefix remapping commandline args. - // If we included the full mapping in the SVH, we could only have - // reproducible builds by compiling from the same directory. So we just - // hash the result of the mapping instead of the mapping itself. - let mut source_file_names: Vec<_> = self - .source_map - .files() - .iter() - .filter(|source_file| CrateNum::from_u32(source_file.crate_of_origin) == LOCAL_CRATE) - .map(|source_file| source_file.name_hash) - .collect(); - - source_file_names.sort_unstable(); - - let crate_hash_input = ( - ((node_hashes, upstream_crates), source_file_names), - (commandline_args_hash, crate_disambiguator.to_fingerprint()), - ); - - let mut stable_hasher = StableHasher::new(); - crate_hash_input.hash_stable(&mut self.hcx, &mut stable_hasher); - let crate_hash: Fingerprint = stable_hasher.finish(); - - let svh = Svh::new(crate_hash.to_smaller_hash()); - (self.map, svh) - } - - fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>) { - debug!("hir_map: {:?} => {:?}", id, entry); - let local_map = &mut self.map[id.owner]; - let i = id.local_id.as_u32() as usize; - let len = local_map.len(); - if i >= len { - local_map.extend(repeat(None).take(i - len + 1)); - } - local_map[id.local_id] = Some(entry); - } - - fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) { - let entry = Entry { - parent: self.parent_node, - dep_node: if self.currently_in_body { - self.current_full_dep_index - } else { - self.current_signature_dep_index - }, - node, - }; - - // Make sure that the DepNode of some node coincides with the HirId - // owner of that node. - if cfg!(debug_assertions) { - let node_id = self.hir_to_node_id[&hir_id]; - assert_eq!(self.definitions.node_to_hir_id(node_id), hir_id); - - if hir_id.owner != self.current_dep_node_owner { - let node_str = match self.definitions.opt_def_index(node_id) { - Some(def_index) => self.definitions.def_path(def_index).to_string_no_crate(), - None => format!("{:?}", node), - }; - - let forgot_str = if hir_id == hir::DUMMY_HIR_ID { - format!("\nMaybe you forgot to lower the node id {:?}?", node_id) - } else { - String::new() - }; - - span_bug!( - span, - "inconsistent DepNode at `{:?}` for `{}`: \ - current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?}){}", - self.source_map.span_to_string(span), - node_str, - self.definitions.def_path(self.current_dep_node_owner).to_string_no_crate(), - self.current_dep_node_owner, - self.definitions.def_path(hir_id.owner).to_string_no_crate(), - hir_id.owner, - forgot_str, - ) - } - } - - self.insert_entry(hir_id, entry); - } - - fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) { - let parent_node = self.parent_node; - self.parent_node = parent_node_id; - f(self); - self.parent_node = parent_node; - } - - fn with_dep_node_owner< - T: for<'b> HashStable<StableHashingContext<'b>>, - F: FnOnce(&mut Self), - >( - &mut self, - dep_node_owner: DefIndex, - item_like: &T, - f: F, - ) { - let prev_owner = self.current_dep_node_owner; - let prev_signature_dep_index = self.current_signature_dep_index; - let prev_full_dep_index = self.current_full_dep_index; - let prev_in_body = self.currently_in_body; - - let def_path_hash = self.definitions.def_path_hash(dep_node_owner); - - let (signature_dep_index, full_dep_index) = alloc_hir_dep_nodes( - self.dep_graph, - &mut self.hcx, - def_path_hash, - item_like, - &mut self.hir_body_nodes, - ); - self.current_signature_dep_index = signature_dep_index; - self.current_full_dep_index = full_dep_index; - - self.current_dep_node_owner = dep_node_owner; - self.currently_in_body = false; - f(self); - self.currently_in_body = prev_in_body; - self.current_dep_node_owner = prev_owner; - self.current_full_dep_index = prev_full_dep_index; - self.current_signature_dep_index = prev_signature_dep_index; - } -} - -impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { - type Map = Map<'hir>; - - /// Because we want to track parent items and so forth, enable - /// deep walking so that we walk nested items in the context of - /// their outer items. - - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> { - panic!("`visit_nested_xxx` must be manually implemented in this visitor"); - } - - fn visit_nested_item(&mut self, item: ItemId) { - debug!("visit_nested_item: {:?}", item); - self.visit_item(self.krate.item(item.id)); - } - - fn visit_nested_trait_item(&mut self, item_id: TraitItemId) { - self.visit_trait_item(self.krate.trait_item(item_id)); - } - - fn visit_nested_impl_item(&mut self, item_id: ImplItemId) { - self.visit_impl_item(self.krate.impl_item(item_id)); - } - - fn visit_nested_body(&mut self, id: BodyId) { - let prev_in_body = self.currently_in_body; - self.currently_in_body = true; - self.visit_body(self.krate.body(id)); - self.currently_in_body = prev_in_body; - } - - fn visit_param(&mut self, param: &'hir Param<'hir>) { - let node = Node::Param(param); - self.insert(param.pat.span, param.hir_id, node); - self.with_parent(param.hir_id, |this| { - intravisit::walk_param(this, param); - }); - } - - fn visit_item(&mut self, i: &'hir Item<'hir>) { - debug!("visit_item: {:?}", i); - debug_assert_eq!( - i.hir_id.owner, - self.definitions.opt_def_index(self.hir_to_node_id[&i.hir_id]).unwrap() - ); - self.with_dep_node_owner(i.hir_id.owner, i, |this| { - this.insert(i.span, i.hir_id, Node::Item(i)); - this.with_parent(i.hir_id, |this| { - if let ItemKind::Struct(ref struct_def, _) = i.kind { - // If this is a tuple or unit-like struct, register the constructor. - if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { - this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def)); - } - } - intravisit::walk_item(this, i); - }); - }); - } - - fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>) { - self.insert(foreign_item.span, foreign_item.hir_id, Node::ForeignItem(foreign_item)); - - self.with_parent(foreign_item.hir_id, |this| { - intravisit::walk_foreign_item(this, foreign_item); - }); - } - - fn visit_generic_param(&mut self, param: &'hir GenericParam<'hir>) { - self.insert(param.span, param.hir_id, Node::GenericParam(param)); - intravisit::walk_generic_param(self, param); - } - - fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { - debug_assert_eq!( - ti.hir_id.owner, - self.definitions.opt_def_index(self.hir_to_node_id[&ti.hir_id]).unwrap() - ); - self.with_dep_node_owner(ti.hir_id.owner, ti, |this| { - this.insert(ti.span, ti.hir_id, Node::TraitItem(ti)); - - this.with_parent(ti.hir_id, |this| { - intravisit::walk_trait_item(this, ti); - }); - }); - } - - fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) { - debug_assert_eq!( - ii.hir_id.owner, - self.definitions.opt_def_index(self.hir_to_node_id[&ii.hir_id]).unwrap() - ); - self.with_dep_node_owner(ii.hir_id.owner, ii, |this| { - this.insert(ii.span, ii.hir_id, Node::ImplItem(ii)); - - this.with_parent(ii.hir_id, |this| { - intravisit::walk_impl_item(this, ii); - }); - }); - } - - fn visit_pat(&mut self, pat: &'hir Pat<'hir>) { - let node = - if let PatKind::Binding(..) = pat.kind { Node::Binding(pat) } else { Node::Pat(pat) }; - self.insert(pat.span, pat.hir_id, node); - - self.with_parent(pat.hir_id, |this| { - intravisit::walk_pat(this, pat); - }); - } - - fn visit_arm(&mut self, arm: &'hir Arm<'hir>) { - let node = Node::Arm(arm); - - self.insert(arm.span, arm.hir_id, node); - - self.with_parent(arm.hir_id, |this| { - intravisit::walk_arm(this, arm); - }); - } - - fn visit_anon_const(&mut self, constant: &'hir AnonConst) { - self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant)); - - self.with_parent(constant.hir_id, |this| { - intravisit::walk_anon_const(this, constant); - }); - } - - fn visit_expr(&mut self, expr: &'hir Expr<'hir>) { - self.insert(expr.span, expr.hir_id, Node::Expr(expr)); - - self.with_parent(expr.hir_id, |this| { - intravisit::walk_expr(this, expr); - }); - } - - fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) { - self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt)); - - self.with_parent(stmt.hir_id, |this| { - intravisit::walk_stmt(this, stmt); - }); - } - - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) { - if let Some(hir_id) = path_segment.hir_id { - self.insert(path_span, hir_id, Node::PathSegment(path_segment)); - } - intravisit::walk_path_segment(self, path_span, path_segment); - } - - fn visit_ty(&mut self, ty: &'hir Ty<'hir>) { - self.insert(ty.span, ty.hir_id, Node::Ty(ty)); - - self.with_parent(ty.hir_id, |this| { - intravisit::walk_ty(this, ty); - }); - } - - fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) { - self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr)); - - self.with_parent(tr.hir_ref_id, |this| { - intravisit::walk_trait_ref(this, tr); - }); - } - - fn visit_fn( - &mut self, - fk: intravisit::FnKind<'hir>, - fd: &'hir FnDecl<'hir>, - b: BodyId, - s: Span, - id: HirId, - ) { - assert_eq!(self.parent_node, id); - intravisit::walk_fn(self, fk, fd, b, s, id); - } - - fn visit_block(&mut self, block: &'hir Block<'hir>) { - self.insert(block.span, block.hir_id, Node::Block(block)); - self.with_parent(block.hir_id, |this| { - intravisit::walk_block(this, block); - }); - } - - fn visit_local(&mut self, l: &'hir Local<'hir>) { - self.insert(l.span, l.hir_id, Node::Local(l)); - self.with_parent(l.hir_id, |this| intravisit::walk_local(this, l)) - } - - fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) { - self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime)); - } - - fn visit_vis(&mut self, visibility: &'hir Visibility<'hir>) { - match visibility.node { - VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {} - VisibilityKind::Restricted { hir_id, .. } => { - self.insert(visibility.span, hir_id, Node::Visibility(visibility)); - self.with_parent(hir_id, |this| { - intravisit::walk_vis(this, visibility); - }); - } - } - } - - fn visit_macro_def(&mut self, macro_def: &'hir MacroDef<'hir>) { - let node_id = self.hir_to_node_id[¯o_def.hir_id]; - let def_index = self.definitions.opt_def_index(node_id).unwrap(); - - self.with_dep_node_owner(def_index, macro_def, |this| { - this.insert(macro_def.span, macro_def.hir_id, Node::MacroDef(macro_def)); - }); - } - - fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) { - self.insert(v.span, v.id, Node::Variant(v)); - self.with_parent(v.id, |this| { - // Register the constructor of this variant. - if let Some(ctor_hir_id) = v.data.ctor_hir_id() { - this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data)); - } - intravisit::walk_variant(this, v, g, item_id); - }); - } - - fn visit_struct_field(&mut self, field: &'hir StructField<'hir>) { - self.insert(field.span, field.hir_id, Node::Field(field)); - self.with_parent(field.hir_id, |this| { - intravisit::walk_struct_field(this, field); - }); - } - - fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) { - // Do not visit the duplicate information in TraitItemRef. We want to - // map the actual nodes, not the duplicate ones in the *Ref. - let TraitItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii; - - self.visit_nested_trait_item(id); - } - - fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef<'hir>) { - // Do not visit the duplicate information in ImplItemRef. We want to - // map the actual nodes, not the duplicate ones in the *Ref. - let ImplItemRef { id, ident: _, kind: _, span: _, vis: _, defaultness: _ } = *ii; - - self.visit_nested_impl_item(id); - } -} - -// This is a wrapper structure that allows determining if span values within -// the wrapped item should be hashed or not. -struct HirItemLike<T> { - item_like: T, - hash_bodies: bool, -} - -impl<'hir, T> HashStable<StableHashingContext<'hir>> for HirItemLike<T> -where - T: HashStable<StableHashingContext<'hir>>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { - hcx.while_hashing_hir_bodies(self.hash_bodies, |hcx| { - self.item_like.hash_stable(hcx, hasher); - }); - } -} diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs deleted file mode 100644 index 048c1f026be..00000000000 --- a/src/librustc/hir/map/definitions.rs +++ /dev/null @@ -1,558 +0,0 @@ -//! 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. - -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::StableHasher; -use rustc_hir as hir; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_index::vec::IndexVec; -use rustc_session::CrateDisambiguator; -use rustc_span::hygiene::ExpnId; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; -use syntax::ast; -use syntax::node_id::NodeMap; - -use std::borrow::Borrow; -use std::fmt::Write; -use std::hash::Hash; - -/// 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, RustcDecodable, RustcEncodable)] -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 - } - - pub fn next_id(&self) -> DefIndex { - DefIndex::from(self.index_to_key.len()) - } - - #[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 add_def_path_hashes_to(&self, cnum: CrateNum, out: &mut FxHashMap<DefPathHash, DefId>) { - out.extend(self.def_path_hashes.iter().enumerate().map(|(index, &hash)| { - let def_id = DefId { krate: cnum, index: DefIndex::from(index) }; - (hash, def_id) - })); - } - - pub fn size(&self) -> usize { - self.index_to_key.len() - } -} - -/// The definition table containing node definitions. -/// It holds the `DefPathTable` for local `DefId`s/`DefPath`s and it also stores a -/// mapping from `NodeId`s to local `DefId`s. -#[derive(Clone, Default)] -pub struct Definitions { - table: DefPathTable, - node_to_def_index: NodeMap<DefIndex>, - def_index_to_node: IndexVec<DefIndex, ast::NodeId>, - pub(super) node_to_hir_id: IndexVec<ast::NodeId, hir::HirId>, - /// 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 `DefIndex` was defined during macro expansion with ID `ExpnId`. - expansions_that_defined: FxHashMap<DefIndex, ExpnId>, - next_disambiguator: FxHashMap<(DefIndex, DefPathData), u32>, - def_index_to_span: FxHashMap<DefIndex, Span>, - /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId` - /// we know what parent node that fragment should be attached to thanks to this table. - invocation_parents: FxHashMap<ExpnId, DefIndex>, - /// Indices of unnamed struct or variant fields with unresolved attributes. - placeholder_field_indices: NodeMap<usize>, -} - -/// 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, RustcEncodable, RustcDecodable)] -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, RustcEncodable, RustcDecodable)] -pub struct DisambiguatedDefPathData { - pub data: DefPathData, - pub disambiguator: u32, -} - -#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -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: data, krate: 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 { - opt_delimiter.map(|d| s.push(d)); - 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, RustcEncodable, RustcDecodable)] -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, -} - -#[derive( - Copy, - Clone, - Hash, - PartialEq, - Eq, - PartialOrd, - Ord, - Debug, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub struct DefPathHash(pub Fingerprint); - -impl Borrow<Fingerprint> for DefPathHash { - #[inline] - fn borrow(&self) -> &Fingerprint { - &self.0 - } -} - -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, index: DefIndex) -> DefKey { - self.table.def_key(index) - } - - #[inline(always)] - pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash { - self.table.def_path_hash(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, index: DefIndex) -> DefPath { - DefPath::make(LOCAL_CRATE, index, |p| self.def_key(p)) - } - - #[inline] - pub fn opt_def_index(&self, node: ast::NodeId) -> Option<DefIndex> { - self.node_to_def_index.get(&node).copied() - } - - #[inline] - pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option<DefId> { - self.opt_def_index(node).map(DefId::local) - } - - #[inline] - pub fn local_def_id(&self, node: ast::NodeId) -> DefId { - self.opt_local_def_id(node).unwrap() - } - - #[inline] - pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> { - if def_id.krate == LOCAL_CRATE { - let node_id = self.def_index_to_node[def_id.index]; - if node_id != ast::DUMMY_NODE_ID { - return Some(node_id); - } - } - None - } - - #[inline] - pub fn as_local_hir_id(&self, def_id: DefId) -> Option<hir::HirId> { - if def_id.krate == LOCAL_CRATE { - let hir_id = self.def_index_to_hir_id(def_id.index); - if hir_id != hir::DUMMY_HIR_ID { Some(hir_id) } else { None } - } else { - None - } - } - - #[inline] - pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId { - self.node_to_hir_id[node_id] - } - - #[inline] - pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> hir::HirId { - let node_id = self.def_index_to_node[def_index]; - self.node_to_hir_id[node_id] - } - - /// Retrieves the span of the given `DefId` if `DefId` is in the local crate, the span exists - /// and it's not `DUMMY_SP`. - #[inline] - pub fn opt_span(&self, def_id: DefId) -> Option<Span> { - if def_id.krate == LOCAL_CRATE { - self.def_index_to_span.get(&def_id.index).copied() - } else { - None - } - } - - /// Adds a root definition (no parent) and a few other reserved definitions. - pub fn create_root_def( - &mut self, - crate_name: &str, - crate_disambiguator: CrateDisambiguator, - ) -> DefIndex { - 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 definition. - let root_index = self.table.allocate(key, def_path_hash); - assert_eq!(root_index, CRATE_DEF_INDEX); - assert!(self.def_index_to_node.is_empty()); - self.def_index_to_node.push(ast::CRATE_NODE_ID); - self.node_to_def_index.insert(ast::CRATE_NODE_ID, root_index); - self.set_invocation_parent(ExpnId::root(), root_index); - - root_index - } - - /// Adds a definition with a parent definition. - pub fn create_def_with_parent( - &mut self, - parent: DefIndex, - node_id: ast::NodeId, - data: DefPathData, - expn_id: ExpnId, - span: Span, - ) -> DefIndex { - debug!( - "create_def_with_parent(parent={:?}, node_id={:?}, data={:?})", - parent, node_id, data - ); - - assert!( - !self.node_to_def_index.contains_key(&node_id), - "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}", - node_id, - data, - self.table.def_key(self.node_to_def_index[&node_id]) - ); - - // The root node must be created with `create_root_def()`. - assert!(data != DefPathData::CrateRoot); - - // Find the next free disambiguator for this key. - let disambiguator = { - let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0); - let disambiguator = *next_disamb; - *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow"); - disambiguator - }; - - let key = DefKey { - parent: Some(parent), - disambiguated_data: DisambiguatedDefPathData { data, disambiguator }, - }; - - let parent_hash = self.table.def_path_hash(parent); - let def_path_hash = key.compute_stable_hash(parent_hash); - - debug!("create_def_with_parent: after disambiguation, key = {:?}", key); - - // Create the definition. - let index = self.table.allocate(key, def_path_hash); - assert_eq!(index.index(), self.def_index_to_node.len()); - self.def_index_to_node.push(node_id); - - // Some things for which we allocate `DefIndex`es don't correspond to - // anything in the AST, so they don't have a `NodeId`. For these cases - // we don't need a mapping from `NodeId` to `DefIndex`. - if node_id != ast::DUMMY_NODE_ID { - debug!("create_def_with_parent: def_index_to_node[{:?} <-> {:?}", index, node_id); - self.node_to_def_index.insert(node_id, index); - } - - if expn_id != ExpnId::root() { - self.expansions_that_defined.insert(index, expn_id); - } - - // The span is added if it isn't dummy. - if !span.is_dummy() { - self.def_index_to_span.insert(index, span); - } - - index - } - - /// Initializes the `ast::NodeId` to `HirId` mapping once it has been generated during - /// AST to HIR lowering. - pub fn init_node_id_to_hir_id_mapping(&mut self, mapping: IndexVec<ast::NodeId, hir::HirId>) { - assert!( - self.node_to_hir_id.is_empty(), - "trying to initialize `NodeId` -> `HirId` mapping twice" - ); - self.node_to_hir_id = mapping; - } - - pub fn expansion_that_defined(&self, index: DefIndex) -> ExpnId { - self.expansions_that_defined.get(&index).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); - } - - pub fn invocation_parent(&self, invoc_id: ExpnId) -> DefIndex { - self.invocation_parents[&invoc_id] - } - - pub fn set_invocation_parent(&mut self, invoc_id: ExpnId, parent: DefIndex) { - let old_parent = self.invocation_parents.insert(invoc_id, parent); - assert!(old_parent.is_none(), "parent `DefIndex` is reset for an invocation"); - } - - pub fn placeholder_field_index(&self, node_id: ast::NodeId) -> usize { - self.placeholder_field_indices[&node_id] - } - - pub fn set_placeholder_field_index(&mut self, node_id: ast::NodeId, index: usize) { - let old_index = self.placeholder_field_indices.insert(node_id, index); - assert!(old_index.is_none(), "placeholder field index is reset for a node ID"); - } -} - -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() - } -} diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs deleted file mode 100644 index a4f9193c0eb..00000000000 --- a/src/librustc/hir/map/hir_id_validator.rs +++ /dev/null @@ -1,175 +0,0 @@ -use crate::hir::map::Map; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator}; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; -use rustc_hir::intravisit; -use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::{HirId, ItemLocalId}; - -pub fn check_crate(hir_map: &Map<'_>, sess: &rustc_session::Session) { - hir_map.dep_graph.assert_ignored(); - - let errors = Lock::new(Vec::new()); - - par_iter(&hir_map.krate.modules).for_each(|(module_id, _)| { - let local_def_id = hir_map.local_def_id(*module_id); - hir_map.visit_item_likes_in_module( - local_def_id, - &mut OuterVisitor { hir_map, errors: &errors }, - ); - }); - - let errors = errors.into_inner(); - - if !errors.is_empty() { - let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2); - sess.delay_span_bug(rustc_span::DUMMY_SP, &message); - } -} - -struct HirIdValidator<'a, 'hir> { - hir_map: &'a Map<'hir>, - owner_def_index: Option<DefIndex>, - hir_ids_seen: FxHashSet<ItemLocalId>, - errors: &'a Lock<Vec<String>>, -} - -struct OuterVisitor<'a, 'hir> { - hir_map: &'a Map<'hir>, - errors: &'a Lock<Vec<String>>, -} - -impl<'a, 'hir> OuterVisitor<'a, 'hir> { - fn new_inner_visitor(&self, hir_map: &'a Map<'hir>) -> HirIdValidator<'a, 'hir> { - HirIdValidator { - hir_map, - owner_def_index: None, - hir_ids_seen: Default::default(), - errors: self.errors, - } - } -} - -impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> { - fn visit_item(&mut self, i: &'hir hir::Item<'hir>) { - let mut inner_visitor = self.new_inner_visitor(self.hir_map); - inner_visitor.check(i.hir_id, |this| intravisit::walk_item(this, i)); - } - - fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) { - let mut inner_visitor = self.new_inner_visitor(self.hir_map); - inner_visitor.check(i.hir_id, |this| intravisit::walk_trait_item(this, i)); - } - - fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) { - let mut inner_visitor = self.new_inner_visitor(self.hir_map); - inner_visitor.check(i.hir_id, |this| intravisit::walk_impl_item(this, i)); - } -} - -impl<'a, 'hir> HirIdValidator<'a, 'hir> { - #[cold] - #[inline(never)] - fn error(&self, f: impl FnOnce() -> String) { - self.errors.lock().push(f()); - } - - fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, hir_id: HirId, walk: F) { - assert!(self.owner_def_index.is_none()); - let owner_def_index = self.hir_map.local_def_id(hir_id).index; - self.owner_def_index = Some(owner_def_index); - walk(self); - - if owner_def_index == CRATE_DEF_INDEX { - return; - } - - // There's always at least one entry for the owning item itself - let max = self - .hir_ids_seen - .iter() - .map(|local_id| local_id.as_usize()) - .max() - .expect("owning item has no entry"); - - if max != self.hir_ids_seen.len() - 1 { - // Collect the missing ItemLocalIds - let missing: Vec<_> = (0..=max as u32) - .filter(|&i| !self.hir_ids_seen.contains(&ItemLocalId::from_u32(i))) - .collect(); - - // Try to map those to something more useful - let mut missing_items = Vec::with_capacity(missing.len()); - - for local_id in missing { - let hir_id = - HirId { owner: owner_def_index, local_id: ItemLocalId::from_u32(local_id) }; - - trace!("missing hir id {:#?}", hir_id); - - missing_items.push(format!( - "[local_id: {}, node:{}]", - local_id, - self.hir_map.node_to_string(hir_id) - )); - } - self.error(|| { - format!( - "ItemLocalIds not assigned densely in {}. \ - Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}", - self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(), - max, - missing_items, - self.hir_ids_seen - .iter() - .map(|&local_id| HirId { owner: owner_def_index, local_id }) - .map(|h| format!("({:?} {})", h, self.hir_map.node_to_string(h))) - .collect::<Vec<_>>() - ) - }); - } - } -} - -impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { - type Map = Map<'hir>; - - fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, Self::Map> { - intravisit::NestedVisitorMap::OnlyBodies(self.hir_map) - } - - fn visit_id(&mut self, hir_id: HirId) { - let owner = self.owner_def_index.expect("no owner_def_index"); - - if hir_id == hir::DUMMY_HIR_ID { - self.error(|| { - format!( - "HirIdValidator: HirId {:?} is invalid", - self.hir_map.node_to_string(hir_id) - ) - }); - return; - } - - if owner != hir_id.owner { - self.error(|| { - format!( - "HirIdValidator: The recorded owner of {} is {} instead of {}", - self.hir_map.node_to_string(hir_id), - self.hir_map.def_path(DefId::local(hir_id.owner)).to_string_no_crate(), - self.hir_map.def_path(DefId::local(owner)).to_string_no_crate() - ) - }); - } - - self.hir_ids_seen.insert(hir_id.local_id); - } - - fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef<'hir>) { - // Explicitly do nothing here. ImplItemRefs contain hir::Visibility - // values that actually belong to an ImplItem instead of the ItemKind::Impl - // we are currently in. So for those it's correct that they have a - // different owner. - } -} diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs deleted file mode 100644 index adda0cde24f..00000000000 --- a/src/librustc/hir/map/mod.rs +++ /dev/null @@ -1,1363 +0,0 @@ -use self::collector::NodeCollector; -pub use self::definitions::{ - DefKey, DefPath, DefPathData, DefPathHash, Definitions, DisambiguatedDefPathData, -}; - -use crate::dep_graph::{DepGraph, DepKind, DepNode, DepNodeIndex}; -use crate::middle::cstore::CrateStoreDyn; -use crate::ty::query::Providers; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::svh::Svh; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX}; -use rustc_hir::intravisit; -use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::print::Nested; -use rustc_hir::*; -use rustc_index::vec::IndexVec; -use rustc_span::hygiene::MacroKind; -use rustc_span::source_map::Spanned; -use rustc_span::symbol::kw; -use rustc_span::Span; -use rustc_target::spec::abi::Abi; -use syntax::ast::{self, Name, NodeId}; - -pub mod blocks; -mod collector; -pub mod definitions; -mod hir_id_validator; - -/// Represents an entry and its parent `HirId`. -#[derive(Copy, Clone, Debug)] -pub struct Entry<'hir> { - parent: HirId, - dep_node: DepNodeIndex, - node: Node<'hir>, -} - -impl<'hir> Entry<'hir> { - fn parent_node(self) -> Option<HirId> { - match self.node { - Node::Crate | Node::MacroDef(_) => None, - _ => Some(self.parent), - } - } - - fn fn_decl(&self) -> Option<&'hir FnDecl<'hir>> { - match self.node { - Node::Item(ref item) => match item.kind { - ItemKind::Fn(ref sig, _, _) => Some(&sig.decl), - _ => None, - }, - - Node::TraitItem(ref item) => match item.kind { - TraitItemKind::Method(ref sig, _) => Some(&sig.decl), - _ => None, - }, - - Node::ImplItem(ref item) => match item.kind { - ImplItemKind::Method(ref sig, _) => Some(&sig.decl), - _ => None, - }, - - Node::Expr(ref expr) => match expr.kind { - ExprKind::Closure(_, ref fn_decl, ..) => Some(fn_decl), - _ => None, - }, - - _ => None, - } - } - - fn fn_sig(&self) -> Option<&'hir FnSig<'hir>> { - match &self.node { - Node::Item(item) => match &item.kind { - ItemKind::Fn(sig, _, _) => Some(sig), - _ => None, - }, - - Node::TraitItem(item) => match &item.kind { - TraitItemKind::Method(sig, _) => Some(sig), - _ => None, - }, - - Node::ImplItem(item) => match &item.kind { - ImplItemKind::Method(sig, _) => Some(sig), - _ => None, - }, - - _ => None, - } - } - - fn associated_body(self) -> Option<BodyId> { - match self.node { - Node::Item(item) => match item.kind { - ItemKind::Const(_, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body) => { - Some(body) - } - _ => None, - }, - - Node::TraitItem(item) => match item.kind { - TraitItemKind::Const(_, Some(body)) - | TraitItemKind::Method(_, TraitMethod::Provided(body)) => Some(body), - _ => None, - }, - - Node::ImplItem(item) => match item.kind { - ImplItemKind::Const(_, body) | ImplItemKind::Method(_, body) => Some(body), - _ => None, - }, - - Node::AnonConst(constant) => Some(constant.body), - - Node::Expr(expr) => match expr.kind { - ExprKind::Closure(.., body, _, _) => Some(body), - _ => None, - }, - - _ => None, - } - } - - fn is_body_owner(self, hir_id: HirId) -> bool { - match self.associated_body() { - Some(b) => b.hir_id == hir_id, - None => false, - } - } -} - -/// This type is effectively a `HashMap<HirId, Entry<'hir>>`, -/// but it is implemented as 2 layers of arrays. -/// - first we have `A = IndexVec<DefIndex, B>` mapping `DefIndex`s to an inner value -/// - which is `B = IndexVec<ItemLocalId, Option<Entry<'hir>>` which gives you the `Entry`. -pub(super) type HirEntryMap<'hir> = IndexVec<DefIndex, IndexVec<ItemLocalId, Option<Entry<'hir>>>>; - -/// Represents a mapping from `NodeId`s to AST elements and their parent `NodeId`s. -#[derive(Clone)] -pub struct Map<'hir> { - krate: &'hir Crate<'hir>, - - pub dep_graph: DepGraph, - - /// The SVH of the local crate. - pub crate_hash: Svh, - - map: HirEntryMap<'hir>, - - definitions: Definitions, - - /// The reverse mapping of `node_to_hir_id`. - hir_to_node_id: FxHashMap<HirId, NodeId>, -} - -struct ParentHirIterator<'map, 'hir> { - current_id: HirId, - map: &'map Map<'hir>, -} - -impl<'map, 'hir> ParentHirIterator<'map, 'hir> { - fn new(current_id: HirId, map: &'map Map<'hir>) -> Self { - Self { current_id, map } - } -} - -impl<'hir> Iterator for ParentHirIterator<'_, 'hir> { - type Item = (HirId, Node<'hir>); - - fn next(&mut self) -> Option<Self::Item> { - if self.current_id == CRATE_HIR_ID { - return None; - } - loop { - // There are nodes that do not have entries, so we need to skip them. - let parent_id = self.map.get_parent_node(self.current_id); - - if parent_id == self.current_id { - self.current_id = CRATE_HIR_ID; - return None; - } - - self.current_id = parent_id; - if let Some(entry) = self.map.find_entry(parent_id) { - return Some((parent_id, entry.node)); - } - // If this `HirId` doesn't have an `Entry`, skip it and look for its `parent_id`. - } - } -} - -impl<'hir> Map<'hir> { - /// This is used internally in the dependency tracking system. - /// Use the `krate` method to ensure your dependency on the - /// crate is tracked. - pub fn untracked_krate(&self) -> &Crate<'hir> { - &self.krate - } - - #[inline] - fn lookup(&self, id: HirId) -> Option<&Entry<'hir>> { - let local_map = self.map.get(id.owner)?; - local_map.get(id.local_id)?.as_ref() - } - - /// Registers a read in the dependency graph of the AST node with - /// the given `id`. This needs to be called each time a public - /// function returns the HIR for a node -- in other words, when it - /// "reveals" the content of a node to the caller (who might not - /// otherwise have had access to those contents, and hence needs a - /// read recorded). If the function just returns a DefId or - /// HirId, no actual content was returned, so no read is needed. - pub fn read(&self, hir_id: HirId) { - if let Some(entry) = self.lookup(hir_id) { - self.dep_graph.read_index(entry.dep_node); - } else { - bug!("called `HirMap::read()` with invalid `HirId`: {:?}", hir_id) - } - } - - #[inline] - pub fn definitions(&self) -> &Definitions { - &self.definitions - } - - pub fn def_key(&self, def_id: DefId) -> DefKey { - assert!(def_id.is_local()); - self.definitions.def_key(def_id.index) - } - - pub fn def_path_from_hir_id(&self, id: HirId) -> Option<DefPath> { - self.opt_local_def_id(id).map(|def_id| self.def_path(def_id)) - } - - pub fn def_path(&self, def_id: DefId) -> DefPath { - assert!(def_id.is_local()); - self.definitions.def_path(def_id.index) - } - - #[inline] - pub fn local_def_id_from_node_id(&self, node: NodeId) -> DefId { - self.opt_local_def_id_from_node_id(node).unwrap_or_else(|| { - let hir_id = self.node_to_hir_id(node); - bug!( - "local_def_id_from_node_id: no entry for `{}`, which has a map of `{:?}`", - node, - self.find_entry(hir_id) - ) - }) - } - - #[inline] - pub fn local_def_id(&self, hir_id: HirId) -> DefId { - self.opt_local_def_id(hir_id).unwrap_or_else(|| { - bug!( - "local_def_id: no entry for `{:?}`, which has a map of `{:?}`", - hir_id, - self.find_entry(hir_id) - ) - }) - } - - #[inline] - pub fn opt_local_def_id(&self, hir_id: HirId) -> Option<DefId> { - let node_id = self.hir_to_node_id(hir_id); - self.definitions.opt_local_def_id(node_id) - } - - #[inline] - pub fn opt_local_def_id_from_node_id(&self, node: NodeId) -> Option<DefId> { - self.definitions.opt_local_def_id(node) - } - - #[inline] - pub fn as_local_node_id(&self, def_id: DefId) -> Option<NodeId> { - self.definitions.as_local_node_id(def_id) - } - - #[inline] - pub fn as_local_hir_id(&self, def_id: DefId) -> Option<HirId> { - self.definitions.as_local_hir_id(def_id) - } - - #[inline] - pub fn hir_to_node_id(&self, hir_id: HirId) -> NodeId { - self.hir_to_node_id[&hir_id] - } - - #[inline] - pub fn node_to_hir_id(&self, node_id: NodeId) -> HirId { - self.definitions.node_to_hir_id(node_id) - } - - #[inline] - pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> HirId { - self.definitions.def_index_to_hir_id(def_index) - } - - #[inline] - pub fn local_def_id_to_hir_id(&self, def_id: LocalDefId) -> HirId { - self.definitions.def_index_to_hir_id(def_id.to_def_id().index) - } - - pub fn def_kind(&self, hir_id: HirId) -> Option<DefKind> { - let node = if let Some(node) = self.find(hir_id) { node } else { return None }; - - Some(match node { - Node::Item(item) => match item.kind { - ItemKind::Static(..) => DefKind::Static, - ItemKind::Const(..) => DefKind::Const, - ItemKind::Fn(..) => DefKind::Fn, - ItemKind::Mod(..) => DefKind::Mod, - ItemKind::OpaqueTy(..) => DefKind::OpaqueTy, - ItemKind::TyAlias(..) => DefKind::TyAlias, - ItemKind::Enum(..) => DefKind::Enum, - ItemKind::Struct(..) => DefKind::Struct, - ItemKind::Union(..) => DefKind::Union, - ItemKind::Trait(..) => DefKind::Trait, - ItemKind::TraitAlias(..) => DefKind::TraitAlias, - ItemKind::ExternCrate(_) - | ItemKind::Use(..) - | ItemKind::ForeignMod(..) - | ItemKind::GlobalAsm(..) - | ItemKind::Impl { .. } => return None, - }, - Node::ForeignItem(item) => match item.kind { - ForeignItemKind::Fn(..) => DefKind::Fn, - ForeignItemKind::Static(..) => DefKind::Static, - ForeignItemKind::Type => DefKind::ForeignTy, - }, - Node::TraitItem(item) => match item.kind { - TraitItemKind::Const(..) => DefKind::AssocConst, - TraitItemKind::Method(..) => DefKind::Method, - TraitItemKind::Type(..) => DefKind::AssocTy, - }, - Node::ImplItem(item) => match item.kind { - ImplItemKind::Const(..) => DefKind::AssocConst, - ImplItemKind::Method(..) => DefKind::Method, - ImplItemKind::TyAlias(..) => DefKind::AssocTy, - ImplItemKind::OpaqueTy(..) => DefKind::AssocOpaqueTy, - }, - Node::Variant(_) => DefKind::Variant, - Node::Ctor(variant_data) => { - // FIXME(eddyb) is this even possible, if we have a `Node::Ctor`? - if variant_data.ctor_hir_id().is_none() { - return None; - } - let ctor_of = match self.find(self.get_parent_node(hir_id)) { - Some(Node::Item(..)) => def::CtorOf::Struct, - Some(Node::Variant(..)) => def::CtorOf::Variant, - _ => unreachable!(), - }; - DefKind::Ctor(ctor_of, def::CtorKind::from_hir(variant_data)) - } - Node::AnonConst(_) - | Node::Field(_) - | Node::Expr(_) - | Node::Stmt(_) - | Node::PathSegment(_) - | Node::Ty(_) - | Node::TraitRef(_) - | Node::Pat(_) - | Node::Binding(_) - | Node::Local(_) - | Node::Param(_) - | Node::Arm(_) - | Node::Lifetime(_) - | Node::Visibility(_) - | Node::Block(_) - | Node::Crate => return None, - Node::MacroDef(_) => DefKind::Macro(MacroKind::Bang), - Node::GenericParam(param) => match param.kind { - GenericParamKind::Lifetime { .. } => return None, - GenericParamKind::Type { .. } => DefKind::TyParam, - GenericParamKind::Const { .. } => DefKind::ConstParam, - }, - }) - } - - fn find_entry(&self, id: HirId) -> Option<Entry<'hir>> { - self.lookup(id).cloned() - } - - pub fn item(&self, id: HirId) -> &'hir Item<'hir> { - self.read(id); - - // N.B., intentionally bypass `self.krate()` so that we - // do not trigger a read of the whole krate here - self.krate.item(id) - } - - pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> { - self.read(id.hir_id); - - // N.B., intentionally bypass `self.krate()` so that we - // do not trigger a read of the whole krate here - self.krate.trait_item(id) - } - - pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> { - self.read(id.hir_id); - - // N.B., intentionally bypass `self.krate()` so that we - // do not trigger a read of the whole krate here - self.krate.impl_item(id) - } - - pub fn body(&self, id: BodyId) -> &'hir Body<'hir> { - self.read(id.hir_id); - - // N.B., intentionally bypass `self.krate()` so that we - // do not trigger a read of the whole krate here - self.krate.body(id) - } - - pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> { - if let Some(entry) = self.find_entry(hir_id) { - entry.fn_decl() - } else { - bug!("no entry for hir_id `{}`", hir_id) - } - } - - pub fn fn_sig_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> { - if let Some(entry) = self.find_entry(hir_id) { - entry.fn_sig() - } else { - bug!("no entry for hir_id `{}`", hir_id) - } - } - - /// Returns the `HirId` that corresponds to the definition of - /// which this is the body of, i.e., a `fn`, `const` or `static` - /// item (possibly associated), a closure, or a `hir::AnonConst`. - pub fn body_owner(&self, BodyId { hir_id }: BodyId) -> HirId { - let parent = self.get_parent_node(hir_id); - assert!(self.lookup(parent).map_or(false, |e| e.is_body_owner(hir_id))); - parent - } - - pub fn body_owner_def_id(&self, id: BodyId) -> DefId { - self.local_def_id(self.body_owner(id)) - } - - /// Given a `HirId`, returns the `BodyId` associated with it, - /// if the node is a body owner, otherwise returns `None`. - pub fn maybe_body_owned_by(&self, hir_id: HirId) -> Option<BodyId> { - if let Some(entry) = self.find_entry(hir_id) { - if self.dep_graph.is_fully_enabled() { - let hir_id_owner = hir_id.owner; - let def_path_hash = self.definitions.def_path_hash(hir_id_owner); - self.dep_graph.read(def_path_hash.to_dep_node(DepKind::HirBody)); - } - - entry.associated_body() - } else { - bug!("no entry for id `{}`", hir_id) - } - } - - /// Given a body owner's id, returns the `BodyId` associated with it. - pub fn body_owned_by(&self, id: HirId) -> BodyId { - self.maybe_body_owned_by(id).unwrap_or_else(|| { - span_bug!( - self.span(id), - "body_owned_by: {} has no associated body", - self.node_to_string(id) - ); - }) - } - - pub fn body_owner_kind(&self, id: HirId) -> BodyOwnerKind { - match self.get(id) { - Node::Item(&Item { kind: ItemKind::Const(..), .. }) - | Node::TraitItem(&TraitItem { kind: TraitItemKind::Const(..), .. }) - | Node::ImplItem(&ImplItem { kind: ImplItemKind::Const(..), .. }) - | Node::AnonConst(_) => BodyOwnerKind::Const, - Node::Ctor(..) - | Node::Item(&Item { kind: ItemKind::Fn(..), .. }) - | Node::TraitItem(&TraitItem { kind: TraitItemKind::Method(..), .. }) - | Node::ImplItem(&ImplItem { kind: ImplItemKind::Method(..), .. }) => BodyOwnerKind::Fn, - Node::Item(&Item { kind: ItemKind::Static(_, m, _), .. }) => BodyOwnerKind::Static(m), - Node::Expr(&Expr { kind: ExprKind::Closure(..), .. }) => BodyOwnerKind::Closure, - node => bug!("{:#?} is not a body node", node), - } - } - - pub fn ty_param_owner(&self, id: HirId) -> HirId { - match self.get(id) { - Node::Item(&Item { kind: ItemKind::Trait(..), .. }) - | Node::Item(&Item { kind: ItemKind::TraitAlias(..), .. }) => id, - Node::GenericParam(_) => self.get_parent_node(id), - _ => bug!("ty_param_owner: {} not a type parameter", self.node_to_string(id)), - } - } - - pub fn ty_param_name(&self, id: HirId) -> Name { - match self.get(id) { - Node::Item(&Item { kind: ItemKind::Trait(..), .. }) - | Node::Item(&Item { kind: ItemKind::TraitAlias(..), .. }) => kw::SelfUpper, - Node::GenericParam(param) => param.name.ident().name, - _ => bug!("ty_param_name: {} not a type parameter", self.node_to_string(id)), - } - } - - pub fn trait_impls(&self, trait_did: DefId) -> &'hir [HirId] { - self.dep_graph.read(DepNode::new_no_params(DepKind::AllLocalTraitImpls)); - - // N.B., intentionally bypass `self.krate()` so that we - // do not trigger a read of the whole krate here - self.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..]) - } - - /// Gets the attributes on the crate. This is preferable to - /// invoking `krate.attrs` because it registers a tighter - /// dep-graph access. - pub fn krate_attrs(&self) -> &'hir [ast::Attribute] { - let def_path_hash = self.definitions.def_path_hash(CRATE_DEF_INDEX); - - self.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir)); - &self.krate.attrs - } - - pub fn get_module(&self, module: DefId) -> (&'hir Mod<'hir>, Span, HirId) { - let hir_id = self.as_local_hir_id(module).unwrap(); - self.read(hir_id); - match self.find_entry(hir_id).unwrap().node { - Node::Item(&Item { span, kind: ItemKind::Mod(ref m), .. }) => (m, span, hir_id), - Node::Crate => (&self.krate.module, self.krate.span, hir_id), - node => panic!("not a module: {:?}", node), - } - } - - pub fn visit_item_likes_in_module<V>(&self, module: DefId, visitor: &mut V) - where - V: ItemLikeVisitor<'hir>, - { - let hir_id = self.as_local_hir_id(module).unwrap(); - - // Read the module so we'll be re-executed if new items - // appear immediately under in the module. If some new item appears - // in some nested item in the module, we'll be re-executed due to reads - // in the expect_* calls the loops below - self.read(hir_id); - - let module = &self.krate.modules[&hir_id]; - - for id in &module.items { - visitor.visit_item(self.expect_item(*id)); - } - - for id in &module.trait_items { - visitor.visit_trait_item(self.expect_trait_item(id.hir_id)); - } - - for id in &module.impl_items { - visitor.visit_impl_item(self.expect_impl_item(id.hir_id)); - } - } - - /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found. - pub fn get(&self, id: HirId) -> Node<'hir> { - // read recorded by `find` - self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id)) - } - - pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> { - self.as_local_hir_id(id).map(|id| self.get(id)) // read recorded by `get` - } - - pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> { - self.get_if_local(id).and_then(|node| match node { - Node::ImplItem(ref impl_item) => Some(&impl_item.generics), - Node::TraitItem(ref trait_item) => Some(&trait_item.generics), - Node::Item(ref item) => match item.kind { - ItemKind::Fn(_, ref generics, _) - | ItemKind::TyAlias(_, ref generics) - | ItemKind::Enum(_, ref generics) - | ItemKind::Struct(_, ref generics) - | ItemKind::Union(_, ref generics) - | ItemKind::Trait(_, _, ref generics, ..) - | ItemKind::TraitAlias(ref generics, _) - | ItemKind::Impl { ref generics, .. } => Some(generics), - _ => None, - }, - _ => None, - }) - } - - /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. - pub fn find(&self, hir_id: HirId) -> Option<Node<'hir>> { - let result = self - .find_entry(hir_id) - .and_then(|entry| if let Node::Crate = entry.node { None } else { Some(entry.node) }); - if result.is_some() { - self.read(hir_id); - } - result - } - - /// Similar to `get_parent`; returns the parent HIR Id, or just `hir_id` if there - /// is no parent. Note that the parent may be `CRATE_HIR_ID`, which is not itself - /// present in the map, so passing the return value of `get_parent_node` to - /// `get` may in fact panic. - /// This function returns the immediate parent in the HIR, whereas `get_parent` - /// returns the enclosing item. Note that this might not be the actual parent - /// node in the HIR -- some kinds of nodes are not in the map and these will - /// never appear as the parent node. Thus, you can always walk the parent nodes - /// from a node to the root of the HIR (unless you get back the same ID here, - /// which can happen if the ID is not in the map itself or is just weird). - pub fn get_parent_node(&self, hir_id: HirId) -> HirId { - if self.dep_graph.is_fully_enabled() { - let hir_id_owner = hir_id.owner; - let def_path_hash = self.definitions.def_path_hash(hir_id_owner); - self.dep_graph.read(def_path_hash.to_dep_node(DepKind::HirBody)); - } - - self.find_entry(hir_id).and_then(|x| x.parent_node()).unwrap_or(hir_id) - } - - /// Checks if the node is an argument. An argument is a local variable whose - /// immediate parent is an item or a closure. - pub fn is_argument(&self, id: HirId) -> bool { - match self.find(id) { - Some(Node::Binding(_)) => (), - _ => return false, - } - match self.find(self.get_parent_node(id)) { - Some(Node::Item(_)) | Some(Node::TraitItem(_)) | Some(Node::ImplItem(_)) => true, - Some(Node::Expr(e)) => match e.kind { - ExprKind::Closure(..) => true, - _ => false, - }, - _ => false, - } - } - - /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context. - /// Used exclusively for diagnostics, to avoid suggestion function calls. - pub fn is_const_context(&self, hir_id: HirId) -> bool { - let parent_id = self.get_parent_item(hir_id); - match self.get(parent_id) { - Node::Item(&Item { kind: ItemKind::Const(..), .. }) - | Node::TraitItem(&TraitItem { kind: TraitItemKind::Const(..), .. }) - | Node::ImplItem(&ImplItem { kind: ImplItemKind::Const(..), .. }) - | Node::AnonConst(_) - | Node::Item(&Item { kind: ItemKind::Static(..), .. }) => true, - Node::Item(&Item { kind: ItemKind::Fn(ref sig, ..), .. }) => { - sig.header.constness == Constness::Const - } - _ => false, - } - } - - /// Wether `hir_id` corresponds to a `mod` or a crate. - pub fn is_hir_id_module(&self, hir_id: HirId) -> bool { - match self.lookup(hir_id) { - Some(Entry { node: Node::Item(Item { kind: ItemKind::Mod(_), .. }), .. }) - | Some(Entry { node: Node::Crate, .. }) => true, - _ => false, - } - } - - /// Retrieves the `HirId` for `id`'s enclosing method, unless there's a - /// `while` or `loop` before reaching it, as block tail returns are not - /// available in them. - /// - /// ``` - /// fn foo(x: usize) -> bool { - /// if x == 1 { - /// true // If `get_return_block` gets passed the `id` corresponding - /// } else { // to this, it will return `foo`'s `HirId`. - /// false - /// } - /// } - /// ``` - /// - /// ``` - /// fn foo(x: usize) -> bool { - /// loop { - /// true // If `get_return_block` gets passed the `id` corresponding - /// } // to this, it will return `None`. - /// false - /// } - /// ``` - pub fn get_return_block(&self, id: HirId) -> Option<HirId> { - let mut iter = ParentHirIterator::new(id, &self).peekable(); - let mut ignore_tail = false; - if let Some(entry) = self.find_entry(id) { - if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = entry.node { - // When dealing with `return` statements, we don't care about climbing only tail - // expressions. - ignore_tail = true; - } - } - while let Some((hir_id, node)) = iter.next() { - if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) { - match next_node { - Node::Block(Block { expr: None, .. }) => return None, - Node::Block(Block { expr: Some(expr), .. }) => { - if hir_id != expr.hir_id { - // The current node is not the tail expression of its parent. - return None; - } - } - _ => {} - } - } - match node { - Node::Item(_) - | Node::ForeignItem(_) - | Node::TraitItem(_) - | Node::Expr(Expr { kind: ExprKind::Closure(..), .. }) - | Node::ImplItem(_) => return Some(hir_id), - Node::Expr(ref expr) => { - match expr.kind { - // Ignore `return`s on the first iteration - ExprKind::Loop(..) | ExprKind::Ret(..) => return None, - _ => {} - } - } - Node::Local(_) => return None, - _ => {} - } - } - None - } - - /// Retrieves the `HirId` for `id`'s parent item, or `id` itself if no - /// parent item is in this map. The "parent item" is the closest parent node - /// in the HIR which is recorded by the map and is an item, either an item - /// in a module, trait, or impl. - pub fn get_parent_item(&self, hir_id: HirId) -> HirId { - for (hir_id, node) in ParentHirIterator::new(hir_id, &self) { - match node { - Node::Crate - | Node::Item(_) - | Node::ForeignItem(_) - | Node::TraitItem(_) - | Node::ImplItem(_) => return hir_id, - _ => {} - } - } - hir_id - } - - /// Returns the `DefId` of `id`'s nearest module parent, or `id` itself if no - /// module parent is in this map. - pub fn get_module_parent(&self, id: HirId) -> DefId { - self.local_def_id(self.get_module_parent_node(id)) - } - - /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no - /// module parent is in this map. - pub fn get_module_parent_node(&self, hir_id: HirId) -> HirId { - for (hir_id, node) in ParentHirIterator::new(hir_id, &self) { - if let Node::Item(&Item { kind: ItemKind::Mod(_), .. }) = node { - return hir_id; - } - } - CRATE_HIR_ID - } - - /// When on a match arm tail expression or on a match arm, give back the enclosing `match` - /// expression. - /// - /// Used by error reporting when there's a type error in a match arm caused by the `match` - /// expression needing to be unit. - pub fn get_match_if_cause(&self, hir_id: HirId) -> Option<&'hir Expr<'hir>> { - for (_, node) in ParentHirIterator::new(hir_id, &self) { - match node { - Node::Item(_) | Node::ForeignItem(_) | Node::TraitItem(_) | Node::ImplItem(_) => { - break; - } - Node::Expr(expr) => match expr.kind { - ExprKind::Match(_, _, _) => return Some(expr), - _ => {} - }, - Node::Stmt(stmt) => match stmt.kind { - StmtKind::Local(_) => break, - _ => {} - }, - _ => {} - } - } - None - } - - /// Returns the nearest enclosing scope. A scope is roughly an item or block. - pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> { - for (hir_id, node) in ParentHirIterator::new(hir_id, &self) { - if match node { - Node::Item(i) => match i.kind { - ItemKind::Fn(..) - | ItemKind::Mod(..) - | ItemKind::Enum(..) - | ItemKind::Struct(..) - | ItemKind::Union(..) - | ItemKind::Trait(..) - | ItemKind::Impl { .. } => true, - _ => false, - }, - Node::ForeignItem(fi) => match fi.kind { - ForeignItemKind::Fn(..) => true, - _ => false, - }, - Node::TraitItem(ti) => match ti.kind { - TraitItemKind::Method(..) => true, - _ => false, - }, - Node::ImplItem(ii) => match ii.kind { - ImplItemKind::Method(..) => true, - _ => false, - }, - Node::Block(_) => true, - _ => false, - } { - return Some(hir_id); - } - } - None - } - - /// Returns the defining scope for an opaque type definition. - pub fn get_defining_scope(&self, id: HirId) -> HirId { - let mut scope = id; - loop { - scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID); - if scope == CRATE_HIR_ID { - return CRATE_HIR_ID; - } - match self.get(scope) { - Node::Item(i) => match i.kind { - ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: None, .. }) => {} - _ => break, - }, - Node::Block(_) => {} - _ => break, - } - } - scope - } - - pub fn get_parent_did(&self, id: HirId) -> DefId { - self.local_def_id(self.get_parent_item(id)) - } - - pub fn get_foreign_abi(&self, hir_id: HirId) -> Abi { - let parent = self.get_parent_item(hir_id); - if let Some(entry) = self.find_entry(parent) { - if let Entry { - node: Node::Item(Item { kind: ItemKind::ForeignMod(ref nm), .. }), .. - } = entry - { - self.read(hir_id); // reveals some of the content of a node - return nm.abi; - } - } - bug!("expected foreign mod or inlined parent, found {}", self.node_to_string(parent)) - } - - pub fn expect_item(&self, id: HirId) -> &'hir Item<'hir> { - match self.find(id) { - // read recorded by `find` - Some(Node::Item(item)) => item, - _ => bug!("expected item, found {}", self.node_to_string(id)), - } - } - - pub fn expect_impl_item(&self, id: HirId) -> &'hir ImplItem<'hir> { - match self.find(id) { - Some(Node::ImplItem(item)) => item, - _ => bug!("expected impl item, found {}", self.node_to_string(id)), - } - } - - pub fn expect_trait_item(&self, id: HirId) -> &'hir TraitItem<'hir> { - match self.find(id) { - Some(Node::TraitItem(item)) => item, - _ => bug!("expected trait item, found {}", self.node_to_string(id)), - } - } - - pub fn expect_variant_data(&self, id: HirId) -> &'hir VariantData<'hir> { - match self.find(id) { - Some(Node::Item(i)) => match i.kind { - ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => { - struct_def - } - _ => bug!("struct ID bound to non-struct {}", self.node_to_string(id)), - }, - Some(Node::Variant(variant)) => &variant.data, - Some(Node::Ctor(data)) => data, - _ => bug!("expected struct or variant, found {}", self.node_to_string(id)), - } - } - - pub fn expect_variant(&self, id: HirId) -> &'hir Variant<'hir> { - match self.find(id) { - Some(Node::Variant(variant)) => variant, - _ => bug!("expected variant, found {}", self.node_to_string(id)), - } - } - - pub fn expect_foreign_item(&self, id: HirId) -> &'hir ForeignItem<'hir> { - match self.find(id) { - Some(Node::ForeignItem(item)) => item, - _ => bug!("expected foreign item, found {}", self.node_to_string(id)), - } - } - - pub fn expect_expr(&self, id: HirId) -> &'hir Expr<'hir> { - match self.find(id) { - // read recorded by find - Some(Node::Expr(expr)) => expr, - _ => bug!("expected expr, found {}", self.node_to_string(id)), - } - } - - pub fn opt_name(&self, id: HirId) -> Option<Name> { - Some(match self.get(id) { - Node::Item(i) => i.ident.name, - Node::ForeignItem(fi) => fi.ident.name, - Node::ImplItem(ii) => ii.ident.name, - Node::TraitItem(ti) => ti.ident.name, - Node::Variant(v) => v.ident.name, - Node::Field(f) => f.ident.name, - Node::Lifetime(lt) => lt.name.ident().name, - Node::GenericParam(param) => param.name.ident().name, - Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name, - Node::Ctor(..) => self.name(self.get_parent_item(id)), - _ => return None, - }) - } - - pub fn name(&self, id: HirId) -> Name { - match self.opt_name(id) { - Some(name) => name, - None => bug!("no name for {}", self.node_to_string(id)), - } - } - - /// Given a node ID, gets a list of attributes associated with the AST - /// corresponding to the node-ID. - pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] { - self.read(id); // reveals attributes on the node - let attrs = match self.find_entry(id).map(|entry| entry.node) { - Some(Node::Param(a)) => Some(&a.attrs[..]), - Some(Node::Local(l)) => Some(&l.attrs[..]), - Some(Node::Item(i)) => Some(&i.attrs[..]), - Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]), - Some(Node::TraitItem(ref ti)) => Some(&ti.attrs[..]), - Some(Node::ImplItem(ref ii)) => Some(&ii.attrs[..]), - Some(Node::Variant(ref v)) => Some(&v.attrs[..]), - Some(Node::Field(ref f)) => Some(&f.attrs[..]), - Some(Node::Expr(ref e)) => Some(&*e.attrs), - Some(Node::Stmt(ref s)) => Some(s.kind.attrs()), - Some(Node::Arm(ref a)) => Some(&*a.attrs), - Some(Node::GenericParam(param)) => Some(¶m.attrs[..]), - // Unit/tuple structs/variants take the attributes straight from - // the struct/variant definition. - Some(Node::Ctor(..)) => return self.attrs(self.get_parent_item(id)), - Some(Node::Crate) => Some(&self.krate.attrs[..]), - _ => None, - }; - attrs.unwrap_or(&[]) - } - - /// Returns an iterator that yields all the hir ids in the map. - fn all_ids<'a>(&'a self) -> impl Iterator<Item = HirId> + 'a { - // This code is a bit awkward because the map is implemented as 2 levels of arrays, - // see the comment on `HirEntryMap`. - // Iterate over all the indices and return a reference to - // local maps and their index given that they exist. - self.map.iter_enumerated().flat_map(move |(owner, local_map)| { - // Iterate over each valid entry in the local map. - local_map.iter_enumerated().filter_map(move |(i, entry)| { - entry.map(move |_| { - // Reconstruct the `HirId` based on the 3 indices we used to find it. - HirId { owner, local_id: i } - }) - }) - }) - } - - /// Returns an iterator that yields the node id's with paths that - /// match `parts`. (Requires `parts` is non-empty.) - /// - /// For example, if given `parts` equal to `["bar", "quux"]`, then - /// the iterator will produce node id's for items with paths - /// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and - /// any other such items it can find in the map. - pub fn nodes_matching_suffix<'a>( - &'a self, - parts: &'a [String], - ) -> impl Iterator<Item = NodeId> + 'a { - let nodes = NodesMatchingSuffix { - map: self, - item_name: parts.last().unwrap(), - in_which: &parts[..parts.len() - 1], - }; - - self.all_ids() - .filter(move |hir| nodes.matches_suffix(*hir)) - .map(move |hir| self.hir_to_node_id(hir)) - } - - pub fn span(&self, hir_id: HirId) -> Span { - self.read(hir_id); // reveals span from node - match self.find_entry(hir_id).map(|entry| entry.node) { - Some(Node::Param(param)) => param.span, - Some(Node::Item(item)) => item.span, - Some(Node::ForeignItem(foreign_item)) => foreign_item.span, - Some(Node::TraitItem(trait_method)) => trait_method.span, - Some(Node::ImplItem(impl_item)) => impl_item.span, - Some(Node::Variant(variant)) => variant.span, - Some(Node::Field(field)) => field.span, - Some(Node::AnonConst(constant)) => self.body(constant.body).value.span, - Some(Node::Expr(expr)) => expr.span, - Some(Node::Stmt(stmt)) => stmt.span, - Some(Node::PathSegment(seg)) => seg.ident.span, - Some(Node::Ty(ty)) => ty.span, - Some(Node::TraitRef(tr)) => tr.path.span, - Some(Node::Binding(pat)) => pat.span, - Some(Node::Pat(pat)) => pat.span, - Some(Node::Arm(arm)) => arm.span, - Some(Node::Block(block)) => block.span, - Some(Node::Ctor(..)) => match self.find(self.get_parent_node(hir_id)) { - Some(Node::Item(item)) => item.span, - Some(Node::Variant(variant)) => variant.span, - _ => unreachable!(), - }, - Some(Node::Lifetime(lifetime)) => lifetime.span, - Some(Node::GenericParam(param)) => param.span, - Some(Node::Visibility(&Spanned { - node: VisibilityKind::Restricted { ref path, .. }, - .. - })) => path.span, - Some(Node::Visibility(v)) => bug!("unexpected Visibility {:?}", v), - Some(Node::Local(local)) => local.span, - Some(Node::MacroDef(macro_def)) => macro_def.span, - Some(Node::Crate) => self.krate.span, - None => bug!("hir::map::Map::span: id not in map: {:?}", hir_id), - } - } - - pub fn span_if_local(&self, id: DefId) -> Option<Span> { - self.as_local_hir_id(id).map(|id| self.span(id)) - } - - pub fn res_span(&self, res: Res) -> Option<Span> { - match res { - Res::Err => None, - Res::Local(id) => Some(self.span(id)), - res => self.span_if_local(res.opt_def_id()?), - } - } - - pub fn node_to_string(&self, id: HirId) -> String { - hir_id_to_string(self, id, true) - } - - pub fn hir_to_user_string(&self, id: HirId) -> String { - hir_id_to_string(self, id, false) - } - - pub fn hir_to_pretty_string(&self, id: HirId) -> String { - print::to_string(self, |s| s.print_node(self.get(id))) - } -} - -impl<'hir> intravisit::Map<'hir> for Map<'hir> { - fn body(&self, id: BodyId) -> &'hir Body<'hir> { - self.body(id) - } - - fn item(&self, id: HirId) -> &'hir Item<'hir> { - self.item(id) - } - - fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> { - self.trait_item(id) - } - - fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> { - self.impl_item(id) - } -} - -pub struct NodesMatchingSuffix<'a> { - map: &'a Map<'a>, - item_name: &'a String, - in_which: &'a [String], -} - -impl<'a> NodesMatchingSuffix<'a> { - /// Returns `true` only if some suffix of the module path for parent - /// matches `self.in_which`. - /// - /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`; - /// returns true if parent's path ends with the suffix - /// `x_0::x_1::...::x_k`. - fn suffix_matches(&self, parent: HirId) -> bool { - let mut cursor = parent; - for part in self.in_which.iter().rev() { - let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) { - None => return false, - Some((node_id, name)) => (node_id, name), - }; - if mod_name.as_str() != *part { - return false; - } - cursor = self.map.get_parent_item(mod_id); - } - return true; - - // Finds the first mod in parent chain for `id`, along with - // that mod's name. - // - // If `id` itself is a mod named `m` with parent `p`, then - // returns `Some(id, m, p)`. If `id` has no mod in its parent - // chain, then returns `None`. - fn find_first_mod_parent(map: &Map<'_>, mut id: HirId) -> Option<(HirId, Name)> { - loop { - if let Node::Item(item) = map.find(id)? { - if item_is_mod(&item) { - return Some((id, item.ident.name)); - } - } - let parent = map.get_parent_item(id); - if parent == id { - return None; - } - id = parent; - } - - fn item_is_mod(item: &Item<'_>) -> bool { - match item.kind { - ItemKind::Mod(_) => true, - _ => false, - } - } - } - } - - // We are looking at some node `n` with a given name and parent - // id; do their names match what I am seeking? - fn matches_names(&self, parent_of_n: HirId, name: Name) -> bool { - name.as_str() == *self.item_name && self.suffix_matches(parent_of_n) - } - - fn matches_suffix(&self, hir: HirId) -> bool { - let name = match self.map.find_entry(hir).map(|entry| entry.node) { - Some(Node::Item(n)) => n.name(), - Some(Node::ForeignItem(n)) => n.name(), - Some(Node::TraitItem(n)) => n.name(), - Some(Node::ImplItem(n)) => n.name(), - Some(Node::Variant(n)) => n.name(), - Some(Node::Field(n)) => n.name(), - _ => return false, - }; - self.matches_names(self.map.get_parent_item(hir), name) - } -} - -trait Named { - fn name(&self) -> Name; -} - -impl<T: Named> Named for Spanned<T> { - fn name(&self) -> Name { - self.node.name() - } -} - -impl Named for Item<'_> { - fn name(&self) -> Name { - self.ident.name - } -} -impl Named for ForeignItem<'_> { - fn name(&self) -> Name { - self.ident.name - } -} -impl Named for Variant<'_> { - fn name(&self) -> Name { - self.ident.name - } -} -impl Named for StructField<'_> { - fn name(&self) -> Name { - self.ident.name - } -} -impl Named for TraitItem<'_> { - fn name(&self) -> Name { - self.ident.name - } -} -impl Named for ImplItem<'_> { - fn name(&self) -> Name { - self.ident.name - } -} - -pub fn map_crate<'hir>( - sess: &rustc_session::Session, - cstore: &CrateStoreDyn, - krate: &'hir Crate<'hir>, - dep_graph: DepGraph, - definitions: Definitions, -) -> Map<'hir> { - let _prof_timer = sess.prof.generic_activity("build_hir_map"); - - // Build the reverse mapping of `node_to_hir_id`. - let hir_to_node_id = definitions - .node_to_hir_id - .iter_enumerated() - .map(|(node_id, &hir_id)| (hir_id, node_id)) - .collect(); - - let (map, crate_hash) = { - let hcx = crate::ich::StableHashingContext::new(sess, krate, &definitions, cstore); - - let mut collector = - NodeCollector::root(sess, krate, &dep_graph, &definitions, &hir_to_node_id, hcx); - intravisit::walk_crate(&mut collector, krate); - - let crate_disambiguator = sess.local_crate_disambiguator(); - let cmdline_args = sess.opts.dep_tracking_hash(); - collector.finalize_and_compute_crate_hash(crate_disambiguator, cstore, cmdline_args) - }; - - let map = Map { krate, dep_graph, crate_hash, map, hir_to_node_id, definitions }; - - sess.time("validate_HIR_map", || { - hir_id_validator::check_crate(&map, sess); - }); - - map -} - -/// Identical to the `PpAnn` implementation for `hir::Crate`, -/// except it avoids creating a dependency on the whole crate. -impl<'hir> print::PpAnn for Map<'hir> { - fn nested(&self, state: &mut print::State<'_>, nested: print::Nested) { - match nested { - Nested::Item(id) => state.print_item(self.expect_item(id.id)), - Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), - Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), - Nested::Body(id) => state.print_expr(&self.body(id).value), - Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat), - } - } -} - -fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { - let id_str = format!(" (hir_id={})", id); - let id_str = if include_id { &id_str[..] } else { "" }; - - let path_str = || { - // This functionality is used for debugging, try to use `TyCtxt` to get - // the user-friendly path, otherwise fall back to stringifying `DefPath`. - crate::ty::tls::with_opt(|tcx| { - if let Some(tcx) = tcx { - let def_id = map.local_def_id(id); - tcx.def_path_str(def_id) - } else if let Some(path) = map.def_path_from_hir_id(id) { - path.data - .into_iter() - .map(|elem| elem.data.to_string()) - .collect::<Vec<_>>() - .join("::") - } else { - String::from("<missing path>") - } - }) - }; - - match map.find(id) { - Some(Node::Item(item)) => { - let item_str = match item.kind { - ItemKind::ExternCrate(..) => "extern crate", - ItemKind::Use(..) => "use", - ItemKind::Static(..) => "static", - ItemKind::Const(..) => "const", - ItemKind::Fn(..) => "fn", - ItemKind::Mod(..) => "mod", - ItemKind::ForeignMod(..) => "foreign mod", - ItemKind::GlobalAsm(..) => "global asm", - ItemKind::TyAlias(..) => "ty", - ItemKind::OpaqueTy(..) => "opaque type", - ItemKind::Enum(..) => "enum", - ItemKind::Struct(..) => "struct", - ItemKind::Union(..) => "union", - ItemKind::Trait(..) => "trait", - ItemKind::TraitAlias(..) => "trait alias", - ItemKind::Impl { .. } => "impl", - }; - format!("{} {}{}", item_str, path_str(), id_str) - } - Some(Node::ForeignItem(_)) => format!("foreign item {}{}", path_str(), id_str), - Some(Node::ImplItem(ii)) => match ii.kind { - ImplItemKind::Const(..) => { - format!("assoc const {} in {}{}", ii.ident, path_str(), id_str) - } - ImplItemKind::Method(..) => format!("method {} in {}{}", ii.ident, path_str(), id_str), - ImplItemKind::TyAlias(_) => { - format!("assoc type {} in {}{}", ii.ident, path_str(), id_str) - } - ImplItemKind::OpaqueTy(_) => { - format!("assoc opaque type {} in {}{}", ii.ident, path_str(), id_str) - } - }, - Some(Node::TraitItem(ti)) => { - let kind = match ti.kind { - TraitItemKind::Const(..) => "assoc constant", - TraitItemKind::Method(..) => "trait method", - TraitItemKind::Type(..) => "assoc type", - }; - - format!("{} {} in {}{}", kind, ti.ident, path_str(), id_str) - } - Some(Node::Variant(ref variant)) => { - format!("variant {} in {}{}", variant.ident, path_str(), id_str) - } - Some(Node::Field(ref field)) => { - format!("field {} in {}{}", field.ident, path_str(), id_str) - } - Some(Node::AnonConst(_)) => format!("const {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Expr(_)) => format!("expr {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Stmt(_)) => format!("stmt {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::PathSegment(_)) => { - format!("path segment {}{}", map.hir_to_pretty_string(id), id_str) - } - Some(Node::Ty(_)) => format!("type {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::TraitRef(_)) => format!("trait_ref {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Binding(_)) => format!("local {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Pat(_)) => format!("pat {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Param(_)) => format!("param {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Arm(_)) => format!("arm {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Block(_)) => format!("block {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Local(_)) => format!("local {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::Ctor(..)) => format!("ctor {}{}", path_str(), id_str), - Some(Node::Lifetime(_)) => format!("lifetime {}{}", map.hir_to_pretty_string(id), id_str), - Some(Node::GenericParam(ref param)) => format!("generic_param {:?}{}", param, id_str), - Some(Node::Visibility(ref vis)) => format!("visibility {:?}{}", vis, id_str), - Some(Node::MacroDef(_)) => format!("macro {}{}", path_str(), id_str), - Some(Node::Crate) => String::from("root_crate"), - None => format!("unknown node{}", id_str), - } -} - -pub fn provide(providers: &mut Providers<'_>) { - providers.def_kind = |tcx, def_id| { - if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { - tcx.hir().def_kind(hir_id) - } else { - bug!("calling local def_kind query provider for upstream DefId: {:?}", def_id); - } - }; -} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs deleted file mode 100644 index 7d48280661a..00000000000 --- a/src/librustc/hir/mod.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! HIR datatypes. See the [rustc guide] for more info. -//! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/hir.html - -pub mod exports; -pub mod map; - -use crate::ty::query::Providers; -use crate::ty::TyCtxt; -use rustc_hir::def_id::LOCAL_CRATE; -use rustc_hir::print; -use rustc_hir::Crate; -use std::ops::Deref; - -/// A wrapper type which allows you to access HIR. -#[derive(Clone)] -pub struct Hir<'tcx> { - tcx: TyCtxt<'tcx>, - map: &'tcx map::Map<'tcx>, -} - -impl<'tcx> Hir<'tcx> { - pub fn krate(&self) -> &'tcx Crate<'tcx> { - self.tcx.hir_crate(LOCAL_CRATE) - } -} - -impl<'tcx> Deref for Hir<'tcx> { - type Target = &'tcx map::Map<'tcx>; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - &self.map - } -} - -impl<'hir> print::PpAnn for Hir<'hir> { - fn nested(&self, state: &mut print::State<'_>, nested: print::Nested) { - self.map.nested(state, nested) - } -} - -impl<'tcx> TyCtxt<'tcx> { - #[inline(always)] - pub fn hir(self) -> Hir<'tcx> { - Hir { tcx: self, map: &self.hir_map } - } -} - -pub fn provide(providers: &mut Providers<'_>) { - providers.hir_crate = |tcx, _| tcx.hir_map.untracked_krate(); - map::provide(providers); -} diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs deleted file mode 100644 index 1a9c5d1f13f..00000000000 --- a/src/librustc/ich/hcx.rs +++ /dev/null @@ -1,281 +0,0 @@ -use crate::hir::map::definitions::Definitions; -use crate::hir::map::DefPathHash; -use crate::ich::{self, CachingSourceMapView}; -use crate::middle::cstore::CrateStore; -use crate::session::Session; -use crate::ty::{fast_reject, TyCtxt}; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; -use rustc_data_structures::sync::Lrc; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, DefIndex}; -use rustc_span::source_map::SourceMap; -use rustc_span::symbol::Symbol; -use rustc_span::{BytePos, SourceFile}; -use syntax::ast; - -use smallvec::SmallVec; -use std::cmp::Ord; - -fn compute_ignored_attr_names() -> FxHashSet<Symbol> { - debug_assert!(ich::IGNORED_ATTRIBUTES.len() > 0); - ich::IGNORED_ATTRIBUTES.iter().map(|&s| s).collect() -} - -/// This is the context state available during incr. comp. hashing. It contains -/// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e., -/// a reference to the `TyCtxt`) and it holds a few caches for speeding up various -/// things (e.g., each `DefId`/`DefPath` is only hashed once). -#[derive(Clone)] -pub struct StableHashingContext<'a> { - sess: &'a Session, - definitions: &'a Definitions, - cstore: &'a dyn CrateStore, - pub(super) body_resolver: BodyResolver<'a>, - hash_spans: bool, - hash_bodies: bool, - pub(super) node_id_hashing_mode: NodeIdHashingMode, - - // Very often, we are hashing something that does not need the - // `CachingSourceMapView`, so we initialize it lazily. - raw_source_map: &'a SourceMap, - caching_source_map: Option<CachingSourceMapView<'a>>, -} - -#[derive(PartialEq, Eq, Clone, Copy)] -pub enum NodeIdHashingMode { - Ignore, - HashDefPath, -} - -/// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`. -/// We could also just store a plain reference to the `hir::Crate` but we want -/// to avoid that the crate is used to get untracked access to all of the HIR. -#[derive(Clone, Copy)] -pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>); - -impl<'tcx> BodyResolver<'tcx> { - /// Returns a reference to the `hir::Body` with the given `BodyId`. - /// **Does not do any tracking**; use carefully. - pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> { - self.0.body(id) - } -} - -impl<'a> StableHashingContext<'a> { - /// The `krate` here is only used for mapping `BodyId`s to `Body`s. - /// Don't use it for anything else or you'll run the risk of - /// leaking data out of the tracking system. - #[inline] - pub fn new( - sess: &'a Session, - krate: &'a hir::Crate<'a>, - definitions: &'a Definitions, - cstore: &'a dyn CrateStore, - ) -> Self { - let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans; - - StableHashingContext { - sess, - body_resolver: BodyResolver(krate), - definitions, - cstore, - caching_source_map: None, - raw_source_map: sess.source_map(), - hash_spans: hash_spans_initial, - hash_bodies: true, - node_id_hashing_mode: NodeIdHashingMode::HashDefPath, - } - } - - #[inline] - pub fn sess(&self) -> &'a Session { - self.sess - } - - #[inline] - pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) { - let prev_hash_bodies = self.hash_bodies; - self.hash_bodies = hash_bodies; - f(self); - self.hash_bodies = prev_hash_bodies; - } - - #[inline] - pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) { - let prev_hash_spans = self.hash_spans; - self.hash_spans = hash_spans; - f(self); - self.hash_spans = prev_hash_spans; - } - - #[inline] - pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>( - &mut self, - mode: NodeIdHashingMode, - f: F, - ) { - let prev = self.node_id_hashing_mode; - self.node_id_hashing_mode = mode; - f(self); - self.node_id_hashing_mode = prev; - } - - #[inline] - pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash { - if def_id.is_local() { - self.definitions.def_path_hash(def_id.index) - } else { - self.cstore.def_path_hash(def_id) - } - } - - #[inline] - pub fn local_def_path_hash(&self, def_index: DefIndex) -> DefPathHash { - self.definitions.def_path_hash(def_index) - } - - #[inline] - pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId { - self.definitions.node_to_hir_id(node_id) - } - - #[inline] - pub fn hash_bodies(&self) -> bool { - self.hash_bodies - } - - #[inline] - pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> { - match self.caching_source_map { - Some(ref mut sm) => sm, - ref mut none => { - *none = Some(CachingSourceMapView::new(self.raw_source_map)); - none.as_mut().unwrap() - } - } - } - - #[inline] - pub fn is_ignored_attr(&self, name: Symbol) -> bool { - thread_local! { - static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names(); - } - IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name)) - } - - pub fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) { - let prev_hash_node_ids = self.node_id_hashing_mode; - self.node_id_hashing_mode = NodeIdHashingMode::Ignore; - - f(self); - - self.node_id_hashing_mode = prev_hash_node_ids; - } -} - -/// Something that can provide a stable hashing context. -pub trait StableHashingContextProvider<'a> { - fn get_stable_hashing_context(&self) -> StableHashingContext<'a>; -} - -impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b T { - fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { - (**self).get_stable_hashing_context() - } -} - -impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b mut T { - fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { - (**self).get_stable_hashing_context() - } -} - -impl StableHashingContextProvider<'tcx> for TyCtxt<'tcx> { - fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> { - (*self).create_stable_hashing_context() - } -} - -impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> { - fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { - self.clone() - } -} - -impl<'a> crate::dep_graph::DepGraphSafe for StableHashingContext<'a> {} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::HirId { - type KeyType = (DefPathHash, hir::ItemLocalId); - - #[inline] - fn to_stable_hash_key( - &self, - hcx: &StableHashingContext<'a>, - ) -> (DefPathHash, hir::ItemLocalId) { - let def_path_hash = hcx.local_def_path_hash(self.owner); - (def_path_hash, self.local_id) - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId { - fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) { - panic!("Node IDs should not appear in incremental state"); - } -} - -impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { - fn hash_spans(&self) -> bool { - self.hash_spans - } - - #[inline] - fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) { - let hcx = self; - hcx.def_path_hash(def_id).hash_stable(hcx, hasher); - } - - fn byte_pos_to_line_and_col( - &mut self, - byte: BytePos, - ) -> Option<(Lrc<SourceFile>, usize, BytePos)> { - self.source_map().byte_pos_to_line_and_col(byte) - } -} - -pub fn hash_stable_trait_impls<'a>( - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher, - blanket_impls: &[DefId], - non_blanket_impls: &FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>, -) { - { - let mut blanket_impls: SmallVec<[_; 8]> = - blanket_impls.iter().map(|&def_id| hcx.def_path_hash(def_id)).collect(); - - if blanket_impls.len() > 1 { - blanket_impls.sort_unstable(); - } - - blanket_impls.hash_stable(hcx, hasher); - } - - { - let mut keys: SmallVec<[_; 8]> = - non_blanket_impls.keys().map(|k| (k, k.map_def(|d| hcx.def_path_hash(d)))).collect(); - keys.sort_unstable_by(|&(_, ref k1), &(_, ref k2)| k1.cmp(k2)); - keys.len().hash_stable(hcx, hasher); - for (key, ref stable_key) in keys { - stable_key.hash_stable(hcx, hasher); - let mut impls: SmallVec<[_; 8]> = - non_blanket_impls[key].iter().map(|&impl_id| hcx.def_path_hash(impl_id)).collect(); - - if impls.len() > 1 { - impls.sort_unstable(); - } - - impls.hash_stable(hcx, hasher); - } - } -} diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs deleted file mode 100644 index eadc9ddeee6..00000000000 --- a/src/librustc/ich/impls_hir.rs +++ /dev/null @@ -1,289 +0,0 @@ -//! This module contains `HashStable` implementations for various HIR data -//! types in no particular order. - -use crate::hir::map::DefPathHash; -use crate::ich::{Fingerprint, NodeIdHashingMode, StableHashingContext}; -use rustc_attr as attr; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; -use rustc_hir as hir; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX}; -use smallvec::SmallVec; -use std::mem; - -impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { - #[inline] - fn hash_hir_id(&mut self, hir_id: hir::HirId, hasher: &mut StableHasher) { - let hcx = self; - match hcx.node_id_hashing_mode { - NodeIdHashingMode::Ignore => { - // Don't do anything. - } - NodeIdHashingMode::HashDefPath => { - let hir::HirId { owner, local_id } = hir_id; - - hcx.local_def_path_hash(owner).hash_stable(hcx, hasher); - local_id.hash_stable(hcx, hasher); - } - } - } - - fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) { - let hcx = self; - if hcx.hash_bodies() { - hcx.body_resolver.body(id).hash_stable(hcx, hasher); - } - } - - fn hash_reference_to_item(&mut self, id: hir::HirId, hasher: &mut StableHasher) { - let hcx = self; - - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - id.hash_stable(hcx, hasher); - }) - } - - fn hash_hir_mod(&mut self, module: &hir::Mod<'_>, hasher: &mut StableHasher) { - let hcx = self; - let hir::Mod { inner: ref inner_span, ref item_ids } = *module; - - inner_span.hash_stable(hcx, hasher); - - // Combining the `DefPathHash`s directly is faster than feeding them - // into the hasher. Because we use a commutative combine, we also don't - // have to sort the array. - let item_ids_hash = item_ids - .iter() - .map(|id| { - let (def_path_hash, local_id) = id.id.to_stable_hash_key(hcx); - debug_assert_eq!(local_id, hir::ItemLocalId::from_u32(0)); - def_path_hash.0 - }) - .fold(Fingerprint::ZERO, |a, b| a.combine_commutative(b)); - - item_ids.len().hash_stable(hcx, hasher); - item_ids_hash.hash_stable(hcx, hasher); - } - - fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) { - self.while_hashing_hir_bodies(true, |hcx| { - let hir::Expr { hir_id: _, ref span, ref kind, ref attrs } = *expr; - - span.hash_stable(hcx, hasher); - kind.hash_stable(hcx, hasher); - attrs.hash_stable(hcx, hasher); - }) - } - - fn hash_hir_ty(&mut self, ty: &hir::Ty<'_>, hasher: &mut StableHasher) { - self.while_hashing_hir_bodies(true, |hcx| { - let hir::Ty { hir_id: _, ref kind, ref span } = *ty; - - kind.hash_stable(hcx, hasher); - span.hash_stable(hcx, hasher); - }) - } - - fn hash_hir_visibility_kind( - &mut self, - vis: &hir::VisibilityKind<'_>, - hasher: &mut StableHasher, - ) { - let hcx = self; - mem::discriminant(vis).hash_stable(hcx, hasher); - match *vis { - hir::VisibilityKind::Public | hir::VisibilityKind::Inherited => { - // No fields to hash. - } - hir::VisibilityKind::Crate(sugar) => { - sugar.hash_stable(hcx, hasher); - } - hir::VisibilityKind::Restricted { ref path, hir_id } => { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - hir_id.hash_stable(hcx, hasher); - }); - path.hash_stable(hcx, hasher); - } - } - } -} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for DefId { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash { - hcx.def_path_hash(*self) - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for LocalDefId { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - hcx.def_path_hash(self.to_def_id()).hash_stable(hcx, hasher); - } -} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for LocalDefId { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash { - hcx.def_path_hash(self.to_def_id()) - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for CrateNum { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - hcx.def_path_hash(DefId { krate: *self, index: CRATE_DEF_INDEX }).hash_stable(hcx, hasher); - } -} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for CrateNum { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash { - let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; - def_id.to_stable_hash_key(hcx) - } -} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::ItemLocalId { - type KeyType = hir::ItemLocalId; - - #[inline] - fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> hir::ItemLocalId { - *self - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitItem<'_> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let hir::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<'a> HashStable<StableHashingContext<'a>> for hir::ImplItem<'_> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let hir::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<'a> HashStable<StableHashingContext<'a>> for hir::Item<'_> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let hir::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); - }); - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for hir::Body<'_> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let hir::Body { params, value, generator_kind } = self; - - hcx.with_node_id_hashing_mode(NodeIdHashingMode::Ignore, |hcx| { - params.hash_stable(hcx, hasher); - value.hash_stable(hcx, hasher); - generator_kind.hash_stable(hcx, hasher); - }); - } -} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::BodyId { - type KeyType = (DefPathHash, hir::ItemLocalId); - - #[inline] - fn to_stable_hash_key( - &self, - hcx: &StableHashingContext<'a>, - ) -> (DefPathHash, hir::ItemLocalId) { - let hir::BodyId { hir_id } = *self; - hir_id.to_stable_hash_key(hcx) - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for hir::def_id::DefIndex { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - hcx.local_def_path_hash(*self).hash_stable(hcx, hasher); - } -} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::def_id::DefIndex { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash { - hcx.local_def_path_hash(*self) - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - let hir::TraitCandidate { def_id, import_ids } = self; - - def_id.hash_stable(hcx, hasher); - import_ids.hash_stable(hcx, hasher); - }); - } -} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate { - type KeyType = (DefPathHash, SmallVec<[(DefPathHash, hir::ItemLocalId); 1]>); - - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType { - let hir::TraitCandidate { def_id, import_ids } = self; - - let import_keys = import_ids - .iter() - .map(|hir_id| (hcx.local_def_path_hash(hir_id.owner), hir_id.local_id)) - .collect(); - (hcx.def_path_hash(*def_id), import_keys) - } -} - -impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InlineAttr { - fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - } -} - -impl<'hir> HashStable<StableHashingContext<'hir>> for attr::OptimizeAttr { - fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - } -} diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs deleted file mode 100644 index d1815d5e320..00000000000 --- a/src/librustc/ich/impls_syntax.rs +++ /dev/null @@ -1,151 +0,0 @@ -//! This module contains `HashStable` implementations for various data types -//! from libsyntax in no particular order. - -use crate::ich::StableHashingContext; - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; -use rustc_span::SourceFile; -use syntax::ast; - -use smallvec::SmallVec; - -impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {} - -impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - if self.len() == 0 { - self.len().hash_stable(hcx, hasher); - return; - } - - // Some attributes are always ignored during hashing. - let filtered: SmallVec<[&ast::Attribute; 8]> = self - .iter() - .filter(|attr| { - !attr.is_doc_comment() - && !attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name)) - }) - .collect(); - - filtered.len().hash_stable(hcx, hasher); - for attr in filtered { - attr.hash_stable(hcx, hasher); - } - } -} - -impl<'ctx> syntax::HashStableContext for StableHashingContext<'ctx> { - fn hash_attr(&mut self, attr: &ast::Attribute, hasher: &mut StableHasher) { - // Make sure that these have been filtered out. - debug_assert!(!attr.ident().map_or(false, |ident| self.is_ignored_attr(ident.name))); - debug_assert!(!attr.is_doc_comment()); - - let ast::Attribute { kind, id: _, style, span } = attr; - if let ast::AttrKind::Normal(item) = kind { - item.hash_stable(self, hasher); - style.hash_stable(self, hasher); - span.hash_stable(self, hasher); - } else { - unreachable!(); - } - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for SourceFile { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let SourceFile { - name: _, // We hash the smaller name_hash instead of this - name_hash, - name_was_remapped, - unmapped_path: _, - crate_of_origin, - // Do not hash the source as it is not encoded - src: _, - src_hash, - external_src: _, - start_pos, - end_pos: _, - ref lines, - ref multibyte_chars, - ref non_narrow_chars, - ref normalized_pos, - } = *self; - - (name_hash as u64).hash_stable(hcx, hasher); - name_was_remapped.hash_stable(hcx, hasher); - - DefId { krate: CrateNum::from_u32(crate_of_origin), index: CRATE_DEF_INDEX } - .hash_stable(hcx, hasher); - - src_hash.hash_stable(hcx, hasher); - - // We only hash the relative position within this source_file - lines.len().hash_stable(hcx, hasher); - for &line in lines.iter() { - stable_byte_pos(line, start_pos).hash_stable(hcx, hasher); - } - - // We only hash the relative position within this source_file - multibyte_chars.len().hash_stable(hcx, hasher); - for &char_pos in multibyte_chars.iter() { - stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher); - } - - non_narrow_chars.len().hash_stable(hcx, hasher); - for &char_pos in non_narrow_chars.iter() { - stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); - } - - normalized_pos.len().hash_stable(hcx, hasher); - for &char_pos in normalized_pos.iter() { - stable_normalized_pos(char_pos, start_pos).hash_stable(hcx, hasher); - } - } -} - -fn stable_byte_pos(pos: ::rustc_span::BytePos, source_file_start: ::rustc_span::BytePos) -> u32 { - pos.0 - source_file_start.0 -} - -fn stable_multibyte_char( - mbc: ::rustc_span::MultiByteChar, - source_file_start: ::rustc_span::BytePos, -) -> (u32, u32) { - let ::rustc_span::MultiByteChar { pos, bytes } = mbc; - - (pos.0 - source_file_start.0, bytes as u32) -} - -fn stable_non_narrow_char( - swc: ::rustc_span::NonNarrowChar, - source_file_start: ::rustc_span::BytePos, -) -> (u32, u32) { - let pos = swc.pos(); - let width = swc.width(); - - (pos.0 - source_file_start.0, width as u32) -} - -fn stable_normalized_pos( - np: ::rustc_span::NormalizedPos, - source_file_start: ::rustc_span::BytePos, -) -> (u32, u32) { - let ::rustc_span::NormalizedPos { pos, diff } = np; - - (pos.0 - source_file_start.0, diff) -} - -impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features { - fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { - // Unfortunately we cannot exhaustively list fields here, since the - // struct is macro generated. - self.declared_lang_features.hash_stable(hcx, hasher); - self.declared_lib_features.hash_stable(hcx, hasher); - - self.walk_feature_fields(|feature_name, value| { - feature_name.hash_stable(hcx, hasher); - value.hash_stable(hcx, hasher); - }); - } -} diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs deleted file mode 100644 index 844250f51a0..00000000000 --- a/src/librustc/ich/impls_ty.rs +++ /dev/null @@ -1,210 +0,0 @@ -//! This module contains `HashStable` implementations for various data types -//! from rustc::ty in no particular order. - -use crate::ich::{Fingerprint, NodeIdHashingMode, StableHashingContext}; -use crate::middle::region; -use crate::mir; -use crate::ty; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; -use std::cell::RefCell; -use std::mem; - -impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for &'tcx ty::List<T> -where - T: HashStable<StableHashingContext<'a>>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - thread_local! { - static CACHE: RefCell<FxHashMap<(usize, usize), Fingerprint>> = - RefCell::new(Default::default()); - } - - let hash = CACHE.with(|cache| { - let key = (self.as_ptr() as usize, self.len()); - if let Some(&hash) = cache.borrow().get(&key) { - return hash; - } - - let mut hasher = StableHasher::new(); - (&self[..]).hash_stable(hcx, &mut hasher); - - let hash: Fingerprint = hasher.finish(); - cache.borrow_mut().insert(key, hash); - hash - }); - - hash.hash_stable(hcx, hasher); - } -} - -impl<'a, 'tcx, T> ToStableHashKey<StableHashingContext<'a>> for &'tcx ty::List<T> -where - T: HashStable<StableHashingContext<'a>>, -{ - type KeyType = Fingerprint; - - #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint { - let mut hasher = StableHasher::new(); - let mut hcx: StableHashingContext<'a> = hcx.clone(); - self.hash_stable(&mut hcx, &mut hasher); - hasher.finish() - } -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::subst::GenericArg<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.unpack().hash_stable(hcx, hasher); - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionKind { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - ty::ReErased | ty::ReStatic => { - // No variant fields to hash for these ... - } - ty::ReEmpty(universe) => { - universe.hash_stable(hcx, hasher); - } - ty::ReLateBound(db, ty::BrAnon(i)) => { - db.hash_stable(hcx, hasher); - i.hash_stable(hcx, hasher); - } - ty::ReLateBound(db, ty::BrNamed(def_id, name)) => { - db.hash_stable(hcx, hasher); - def_id.hash_stable(hcx, hasher); - name.hash_stable(hcx, hasher); - } - ty::ReLateBound(db, ty::BrEnv) => { - db.hash_stable(hcx, hasher); - } - ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => { - def_id.hash_stable(hcx, hasher); - index.hash_stable(hcx, hasher); - name.hash_stable(hcx, hasher); - } - ty::ReScope(scope) => { - scope.hash_stable(hcx, hasher); - } - ty::ReFree(ref free_region) => { - free_region.hash_stable(hcx, hasher); - } - ty::ReClosureBound(vid) => { - vid.hash_stable(hcx, hasher); - } - ty::ReVar(..) | ty::RePlaceholder(..) => { - bug!("StableHasher: unexpected region {:?}", *self) - } - } - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionVid { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.index().hash_stable(hcx, hasher); - } -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::ConstVid<'tcx> { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.index.hash_stable(hcx, hasher); - } -} - -impl<'tcx> HashStable<StableHashingContext<'tcx>> for ty::BoundVar { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { - self.index().hash_stable(hcx, hasher); - } -} - -impl<'a, T> HashStable<StableHashingContext<'a>> for ty::Binder<T> -where - T: HashStable<StableHashingContext<'a>>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.skip_binder().hash_stable(hcx, hasher); - } -} - -// AllocIds get resolved to whatever they point to (to be stable) -impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - ty::tls::with_opt(|tcx| { - trace!("hashing {:?}", *self); - let tcx = tcx.expect("can't hash AllocIds during hir lowering"); - let alloc_kind = tcx.alloc_map.lock().get(*self); - alloc_kind.hash_stable(hcx, hasher); - }); - } -} - -// `Relocations` with default type parameters is a sorted map. -impl<'a, Tag> HashStable<StableHashingContext<'a>> for mir::interpret::Relocations<Tag> -where - Tag: HashStable<StableHashingContext<'a>>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.len().hash_stable(hcx, hasher); - for reloc in self.iter() { - reloc.hash_stable(hcx, hasher); - } - } -} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for region::Scope { - type KeyType = region::Scope; - - #[inline] - fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> region::Scope { - *self - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for ty::TyVid { - fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) { - // `TyVid` values are confined to an inference context and hence - // should not be hashed. - bug!("ty::TyKind::hash_stable() - can't hash a TyVid {:?}.", *self) - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for ty::IntVid { - fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) { - // `IntVid` values are confined to an inference context and hence - // should not be hashed. - bug!("ty::TyKind::hash_stable() - can't hash an IntVid {:?}.", *self) - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for ty::FloatVid { - fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) { - // `FloatVid` values are confined to an inference context and hence - // should not be hashed. - bug!("ty::TyKind::hash_stable() - can't hash a FloatVid {:?}.", *self) - } -} - -impl<'a, T> HashStable<StableHashingContext<'a>> for ty::steal::Steal<T> -where - T: HashStable<StableHashingContext<'a>>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.borrow().hash_stable(hcx, hasher); - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for crate::middle::privacy::AccessLevels { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - let crate::middle::privacy::AccessLevels { ref map } = *self; - - map.hash_stable(hcx, hasher); - }); - } -} diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs deleted file mode 100644 index 2c4618dcd42..00000000000 --- a/src/librustc/ich/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! ICH - Incremental Compilation Hash - -pub use self::hcx::{ - hash_stable_trait_impls, NodeIdHashingMode, StableHashingContext, StableHashingContextProvider, -}; -crate use rustc_data_structures::fingerprint::Fingerprint; -use rustc_span::symbol::{sym, Symbol}; -pub use rustc_span::CachingSourceMapView; - -mod hcx; - -mod impls_hir; -mod impls_syntax; -mod impls_ty; - -pub const IGNORED_ATTRIBUTES: &[Symbol] = &[ - sym::cfg, - sym::rustc_if_this_changed, - sym::rustc_then_this_would_need, - sym::rustc_dirty, - sym::rustc_clean, - sym::rustc_partition_reused, - sym::rustc_partition_codegened, - sym::rustc_expected_cgu_reuse, -]; diff --git a/src/librustc/infer/canonical.rs b/src/librustc/infer/canonical.rs deleted file mode 100644 index 76d0d57e233..00000000000 --- a/src/librustc/infer/canonical.rs +++ /dev/null @@ -1,357 +0,0 @@ -//! **Canonicalization** is the key to constructing a query in the -//! middle of type inference. Ordinarily, it is not possible to store -//! types from type inference in query keys, because they contain -//! references to inference variables whose lifetimes are too short -//! and so forth. Canonicalizing a value T1 using `canonicalize_query` -//! produces two things: -//! -//! - a value T2 where each unbound inference variable has been -//! replaced with a **canonical variable**; -//! - a map M (of type `CanonicalVarValues`) from those canonical -//! variables back to the original. -//! -//! We can then do queries using T2. These will give back constraints -//! on the canonical variables which can be translated, using the map -//! M, into constraints in our source context. This process of -//! translating the results back is done by the -//! `instantiate_query_result` method. -//! -//! For a more detailed look at what is happening here, check -//! out the [chapter in the rustc guide][c]. -//! -//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html - -use crate::infer::MemberConstraint; -use crate::ty::subst::GenericArg; -use crate::ty::{self, BoundVar, List, Region, TyCtxt}; -use rustc_index::vec::IndexVec; -use rustc_macros::HashStable; -use rustc_serialize::UseSpecializedDecodable; -use smallvec::SmallVec; -use std::ops::Index; - -/// A "canonicalized" type `V` is one where all free inference -/// variables have been rewritten to "canonical vars". These are -/// numbered starting from 0 in order of first appearance. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] -#[derive(HashStable, TypeFoldable, Lift)] -pub struct Canonical<'tcx, V> { - pub max_universe: ty::UniverseIndex, - pub variables: CanonicalVarInfos<'tcx>, - pub value: V, -} - -pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo>; - -impl<'tcx> UseSpecializedDecodable for CanonicalVarInfos<'tcx> {} - -/// A set of values corresponding to the canonical variables from some -/// `Canonical`. You can give these values to -/// `canonical_value.substitute` to substitute them into the canonical -/// value at the right places. -/// -/// When you canonicalize a value `V`, you get back one of these -/// vectors with the original values that were replaced by canonical -/// variables. You will need to supply it later to instantiate the -/// canonicalized query response. -#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] -#[derive(HashStable, TypeFoldable, Lift)] -pub struct CanonicalVarValues<'tcx> { - pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>, -} - -/// When we canonicalize a value to form a query, we wind up replacing -/// various parts of it with canonical variables. This struct stores -/// those replaced bits to remember for when we process the query -/// result. -#[derive(Clone, Debug)] -pub struct OriginalQueryValues<'tcx> { - /// Map from the universes that appear in the query to the - /// universes in the caller context. For the time being, we only - /// ever put ROOT values into the query, so this map is very - /// simple. - pub universe_map: SmallVec<[ty::UniverseIndex; 4]>, - - /// This is equivalent to `CanonicalVarValues`, but using a - /// `SmallVec` yields a significant performance win. - pub var_values: SmallVec<[GenericArg<'tcx>; 8]>, -} - -impl Default for OriginalQueryValues<'tcx> { - fn default() -> Self { - let mut universe_map = SmallVec::default(); - universe_map.push(ty::UniverseIndex::ROOT); - - Self { universe_map, var_values: SmallVec::default() } - } -} - -/// Information about a canonical variable that is included with the -/// canonical value. This is sufficient information for code to create -/// a copy of the canonical value in some other inference context, -/// with fresh inference variables replacing the canonical values. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)] -pub struct CanonicalVarInfo { - pub kind: CanonicalVarKind, -} - -impl CanonicalVarInfo { - pub fn universe(&self) -> ty::UniverseIndex { - self.kind.universe() - } - - pub fn is_existential(&self) -> bool { - match self.kind { - CanonicalVarKind::Ty(_) => true, - CanonicalVarKind::PlaceholderTy(_) => false, - CanonicalVarKind::Region(_) => true, - CanonicalVarKind::PlaceholderRegion(..) => false, - CanonicalVarKind::Const(_) => true, - CanonicalVarKind::PlaceholderConst(_) => false, - } - } -} - -/// Describes the "kind" of the canonical variable. This is a "kind" -/// in the type-theory sense of the term -- i.e., a "meta" type system -/// that analyzes type-like values. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)] -pub enum CanonicalVarKind { - /// Some kind of type inference variable. - Ty(CanonicalTyVarKind), - - /// A "placeholder" that represents "any type". - PlaceholderTy(ty::PlaceholderType), - - /// Region variable `'?R`. - Region(ty::UniverseIndex), - - /// A "placeholder" that represents "any region". Created when you - /// are solving a goal like `for<'a> T: Foo<'a>` to represent the - /// bound region `'a`. - PlaceholderRegion(ty::PlaceholderRegion), - - /// Some kind of const inference variable. - Const(ty::UniverseIndex), - - /// A "placeholder" that represents "any const". - PlaceholderConst(ty::PlaceholderConst), -} - -impl CanonicalVarKind { - pub fn universe(self) -> ty::UniverseIndex { - match self { - CanonicalVarKind::Ty(kind) => match kind { - CanonicalTyVarKind::General(ui) => ui, - CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT, - }, - - CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe, - CanonicalVarKind::Region(ui) => ui, - CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe, - CanonicalVarKind::Const(ui) => ui, - CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe, - } - } -} - -/// Rust actually has more than one category of type variables; -/// notably, the type variables we create for literals (e.g., 22 or -/// 22.) can only be instantiated with integral/float types (e.g., -/// usize or f32). In order to faithfully reproduce a type, we need to -/// know what set of types a given type variable can be unified with. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)] -pub enum CanonicalTyVarKind { - /// General type variable `?T` that can be unified with arbitrary types. - General(ty::UniverseIndex), - - /// Integral type variable `?I` (that can only be unified with integral types). - Int, - - /// Floating-point type variable `?F` (that can only be unified with float types). - Float, -} - -/// After we execute a query with a canonicalized key, we get back a -/// `Canonical<QueryResponse<..>>`. You can use -/// `instantiate_query_result` to access the data in this result. -#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] -pub struct QueryResponse<'tcx, R> { - pub var_values: CanonicalVarValues<'tcx>, - pub region_constraints: QueryRegionConstraints<'tcx>, - pub certainty: Certainty, - pub value: R, -} - -#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)] -pub struct QueryRegionConstraints<'tcx> { - pub outlives: Vec<QueryOutlivesConstraint<'tcx>>, - pub member_constraints: Vec<MemberConstraint<'tcx>>, -} - -impl QueryRegionConstraints<'_> { - /// Represents an empty (trivially true) set of region - /// constraints. - pub fn is_empty(&self) -> bool { - self.outlives.is_empty() && self.member_constraints.is_empty() - } -} - -pub type Canonicalized<'tcx, V> = Canonical<'tcx, V>; - -pub type CanonicalizedQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>; - -/// Indicates whether or not we were able to prove the query to be -/// true. -#[derive(Copy, Clone, Debug, HashStable)] -pub enum Certainty { - /// The query is known to be true, presuming that you apply the - /// given `var_values` and the region-constraints are satisfied. - Proven, - - /// The query is not known to be true, but also not known to be - /// false. The `var_values` represent *either* values that must - /// hold in order for the query to be true, or helpful tips that - /// *might* make it true. Currently rustc's trait solver cannot - /// distinguish the two (e.g., due to our preference for where - /// clauses over impls). - /// - /// After some unifiations and things have been done, it makes - /// sense to try and prove again -- of course, at that point, the - /// canonical form will be different, making this a distinct - /// query. - Ambiguous, -} - -impl Certainty { - pub fn is_proven(&self) -> bool { - match self { - Certainty::Proven => true, - Certainty::Ambiguous => false, - } - } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } -} - -impl<'tcx, R> QueryResponse<'tcx, R> { - pub fn is_proven(&self) -> bool { - self.certainty.is_proven() - } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } -} - -impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> { - pub fn is_proven(&self) -> bool { - self.value.is_proven() - } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } -} - -impl<'tcx, V> Canonical<'tcx, V> { - /// Allows you to map the `value` of a canonical while keeping the - /// same set of bound variables. - /// - /// **WARNING:** This function is very easy to mis-use, hence the - /// name! In particular, the new value `W` must use all **the - /// same type/region variables** in **precisely the same order** - /// as the original! (The ordering is defined by the - /// `TypeFoldable` implementation of the type in question.) - /// - /// An example of a **correct** use of this: - /// - /// ```rust,ignore (not real code) - /// let a: Canonical<'_, T> = ...; - /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, )); - /// ``` - /// - /// An example of an **incorrect** use of this: - /// - /// ```rust,ignore (not real code) - /// let a: Canonical<'tcx, T> = ...; - /// let ty: Ty<'tcx> = ...; - /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty)); - /// ``` - pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> { - let Canonical { max_universe, variables, value } = self; - Canonical { max_universe, variables, value: map_op(value) } - } -} - -pub type QueryOutlivesConstraint<'tcx> = - ty::Binder<ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>; - -CloneTypeFoldableAndLiftImpls! { - crate::infer::canonical::Certainty, - crate::infer::canonical::CanonicalVarInfo, - crate::infer::canonical::CanonicalVarKind, -} - -CloneTypeFoldableImpls! { - for <'tcx> { - crate::infer::canonical::CanonicalVarInfos<'tcx>, - } -} - -impl<'tcx> CanonicalVarValues<'tcx> { - pub fn len(&self) -> usize { - self.var_values.len() - } - - /// Makes an identity substitution from this one: each bound var - /// is matched to the same bound var, preserving the original kinds. - /// For example, if we have: - /// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]` - /// we'll return a substitution `subst` with: - /// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`. - pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self { - use crate::ty::subst::GenericArgKind; - - CanonicalVarValues { - var_values: self - .var_values - .iter() - .zip(0..) - .map(|(kind, i)| match kind.unpack() { - GenericArgKind::Type(..) => { - tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into() - } - GenericArgKind::Lifetime(..) => tcx - .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i))) - .into(), - GenericArgKind::Const(ct) => tcx - .mk_const(ty::Const { - ty: ct.ty, - val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)), - }) - .into(), - }) - .collect(), - } - } -} - -impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> { - type Item = GenericArg<'tcx>; - type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>; - - fn into_iter(self) -> Self::IntoIter { - self.var_values.iter().cloned() - } -} - -impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> { - type Output = GenericArg<'tcx>; - - fn index(&self, value: BoundVar) -> &GenericArg<'tcx> { - &self.var_values[value] - } -} diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs deleted file mode 100644 index 497d3811f28..00000000000 --- a/src/librustc/infer/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -pub mod canonical; -pub mod unify_key; - -use crate::ty::Region; -use crate::ty::Ty; -use rustc_data_structures::sync::Lrc; -use rustc_hir::def_id::DefId; -use rustc_span::Span; - -/// Requires that `region` must be equal to one of the regions in `choice_regions`. -/// We often denote this using the syntax: -/// -/// ``` -/// R0 member of [O1..On] -/// ``` -#[derive(Debug, Clone, HashStable, TypeFoldable, Lift)] -pub struct MemberConstraint<'tcx> { - /// The `DefId` of the opaque type causing this constraint: used for error reporting. - pub opaque_type_def_id: DefId, - - /// The span where the hidden type was instantiated. - pub definition_span: Span, - - /// The hidden type in which `member_region` appears: used for error reporting. - pub hidden_ty: Ty<'tcx>, - - /// The region `R0`. - pub member_region: Region<'tcx>, - - /// The options `O1..On`. - pub choice_regions: Lrc<Vec<Region<'tcx>>>, -} diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs deleted file mode 100644 index e205453a48c..00000000000 --- a/src/librustc/infer/unify_key.rs +++ /dev/null @@ -1,227 +0,0 @@ -use crate::ty::{self, FloatVarValue, InferConst, IntVarValue, Ty, TyCtxt}; -use rustc_data_structures::unify::InPlace; -use rustc_data_structures::unify::{EqUnifyValue, NoError, UnificationTable, UnifyKey, UnifyValue}; -use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; - -use std::cmp; -use std::marker::PhantomData; - -pub trait ToType { - fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; -} - -/// Raw `TyVid` are used as the unification key for `sub_relations`; -/// they carry no values. -impl UnifyKey for ty::TyVid { - type Value = (); - fn index(&self) -> u32 { - self.index - } - fn from_index(i: u32) -> ty::TyVid { - ty::TyVid { index: i } - } - fn tag() -> &'static str { - "TyVid" - } -} - -impl UnifyKey for ty::IntVid { - type Value = Option<IntVarValue>; - fn index(&self) -> u32 { - self.index - } - fn from_index(i: u32) -> ty::IntVid { - ty::IntVid { index: i } - } - fn tag() -> &'static str { - "IntVid" - } -} - -impl EqUnifyValue for IntVarValue {} - -#[derive(PartialEq, Copy, Clone, Debug)] -pub struct RegionVidKey { - /// The minimum region vid in the unification set. This is needed - /// to have a canonical name for a type to prevent infinite - /// recursion. - pub min_vid: ty::RegionVid, -} - -impl UnifyValue for RegionVidKey { - type Error = NoError; - - fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> { - let min_vid = if value1.min_vid.index() < value2.min_vid.index() { - value1.min_vid - } else { - value2.min_vid - }; - - Ok(RegionVidKey { min_vid }) - } -} - -impl UnifyKey for ty::RegionVid { - type Value = RegionVidKey; - fn index(&self) -> u32 { - u32::from(*self) - } - fn from_index(i: u32) -> ty::RegionVid { - ty::RegionVid::from(i) - } - fn tag() -> &'static str { - "RegionVid" - } -} - -impl ToType for IntVarValue { - fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match *self { - ty::IntType(i) => tcx.mk_mach_int(i), - ty::UintType(i) => tcx.mk_mach_uint(i), - } - } -} - -// Floating point type keys - -impl UnifyKey for ty::FloatVid { - type Value = Option<FloatVarValue>; - fn index(&self) -> u32 { - self.index - } - fn from_index(i: u32) -> ty::FloatVid { - ty::FloatVid { index: i } - } - fn tag() -> &'static str { - "FloatVid" - } -} - -impl EqUnifyValue for FloatVarValue {} - -impl ToType for FloatVarValue { - fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.mk_mach_float(self.0) - } -} - -// Generic consts. - -#[derive(Copy, Clone, Debug)] -pub struct ConstVariableOrigin { - pub kind: ConstVariableOriginKind, - pub span: Span, -} - -/// Reasons to create a const inference variable -#[derive(Copy, Clone, Debug)] -pub enum ConstVariableOriginKind { - MiscVariable, - ConstInference, - ConstParameterDefinition(Symbol), - SubstitutionPlaceholder, -} - -#[derive(Copy, Clone, Debug)] -pub enum ConstVariableValue<'tcx> { - Known { value: &'tcx ty::Const<'tcx> }, - Unknown { universe: ty::UniverseIndex }, -} - -impl<'tcx> ConstVariableValue<'tcx> { - /// If this value is known, returns the const it is known to be. - /// Otherwise, `None`. - pub fn known(&self) -> Option<&'tcx ty::Const<'tcx>> { - match *self { - ConstVariableValue::Unknown { .. } => None, - ConstVariableValue::Known { value } => Some(value), - } - } - - pub fn is_unknown(&self) -> bool { - match *self { - ConstVariableValue::Unknown { .. } => true, - ConstVariableValue::Known { .. } => false, - } - } -} - -#[derive(Copy, Clone, Debug)] -pub struct ConstVarValue<'tcx> { - pub origin: ConstVariableOrigin, - pub val: ConstVariableValue<'tcx>, -} - -impl<'tcx> UnifyKey for ty::ConstVid<'tcx> { - type Value = ConstVarValue<'tcx>; - fn index(&self) -> u32 { - self.index - } - fn from_index(i: u32) -> Self { - ty::ConstVid { index: i, phantom: PhantomData } - } - fn tag() -> &'static str { - "ConstVid" - } -} - -impl<'tcx> UnifyValue for ConstVarValue<'tcx> { - type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>); - - fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> { - let val = match (value1.val, value2.val) { - (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => { - bug!("equating two const variables, both of which have known values") - } - - // If one side is known, prefer that one. - (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => { - Ok(value1.val) - } - (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => { - Ok(value2.val) - } - - // If both sides are *unknown*, it hardly matters, does it? - ( - ConstVariableValue::Unknown { universe: universe1 }, - ConstVariableValue::Unknown { universe: universe2 }, - ) => { - // If we unify two unbound variables, ?T and ?U, then whatever - // value they wind up taking (which must be the same value) must - // be nameable by both universes. Therefore, the resulting - // universe is the minimum of the two universes, because that is - // the one which contains the fewest names in scope. - let universe = cmp::min(universe1, universe2); - Ok(ConstVariableValue::Unknown { universe }) - } - }?; - - Ok(ConstVarValue { - origin: ConstVariableOrigin { - kind: ConstVariableOriginKind::ConstInference, - span: DUMMY_SP, - }, - val, - }) - } -} - -impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {} - -pub fn replace_if_possible( - table: &mut UnificationTable<InPlace<ty::ConstVid<'tcx>>>, - c: &'tcx ty::Const<'tcx>, -) -> &'tcx ty::Const<'tcx> { - if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = c { - match table.probe_value(*vid).val.known() { - Some(c) => c, - None => c, - } - } else { - c - } -} diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs deleted file mode 100644 index 055d70effc6..00000000000 --- a/src/librustc/lib.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! The "main crate" of the Rust compiler. This crate contains common -//! type definitions that are used by the other crates in the rustc -//! "family". Some prominent examples (note that each of these modules -//! has their own README with further details). -//! -//! - **HIR.** The "high-level (H) intermediate representation (IR)" is -//! defined in the `hir` module. -//! - **MIR.** The "mid-level (M) intermediate representation (IR)" is -//! defined in the `mir` module. This module contains only the -//! *definition* of the MIR; the passes that transform and operate -//! on MIR are found in `librustc_mir` crate. -//! - **Types.** The internal representation of types used in rustc is -//! defined in the `ty` module. This includes the **type context** -//! (or `tcx`), which is the central context during most of -//! compilation, containing the interners and other things. -//! -//! For more information about how rustc works, see the [rustc guide]. -//! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/ -//! -//! # Note -//! -//! This API is completely unstable and subject to change. - -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(bool_to_option)] -#![feature(box_patterns)] -#![feature(box_syntax)] -#![feature(const_transmute)] -#![feature(core_intrinsics)] -#![feature(drain_filter)] -#![feature(never_type)] -#![feature(exhaustive_patterns)] -#![feature(marker_trait_attr)] -#![feature(extern_types)] -#![feature(nll)] -#![feature(option_expect_none)] -#![feature(range_is_empty)] -#![feature(specialization)] -#![feature(trusted_len)] -#![feature(vec_remove_item)] -#![feature(stmt_expr_attributes)] -#![feature(test)] -#![feature(in_band_lifetimes)] -#![feature(crate_visibility_modifier)] -#![feature(associated_type_bounds)] -#![feature(rustc_attrs)] -#![feature(hash_raw_entry)] -#![feature(int_error_matching)] -#![recursion_limit = "512"] - -#[macro_use] -extern crate bitflags; -#[macro_use] -extern crate scoped_tls; -#[macro_use] -extern crate rustc_macros; -#[macro_use] -extern crate rustc_data_structures; -#[macro_use] -extern crate log; -#[macro_use] -extern crate smallvec; - -#[cfg(test)] -mod tests; - -#[macro_use] -mod macros; - -#[macro_use] -pub mod query; - -#[macro_use] -pub mod arena; -pub mod dep_graph; -pub mod hir; -pub mod ich; -pub mod infer; -pub mod lint; -pub mod middle; -pub mod mir; -pub use rustc_session as session; -pub mod traits; -pub mod ty; - -pub mod util { - pub mod bug; - pub mod common; -} - -// Allows macros to refer to this crate as `::rustc` -extern crate self as rustc; diff --git a/src/librustc/lint.rs b/src/librustc/lint.rs deleted file mode 100644 index 004835b230a..00000000000 --- a/src/librustc/lint.rs +++ /dev/null @@ -1,401 +0,0 @@ -use std::cmp; - -use crate::ich::StableHashingContext; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId}; -use rustc_hir::HirId; -pub use rustc_session::lint::{builtin, Level, Lint, LintId, LintPass}; -use rustc_session::{DiagnosticMessageId, Session}; -use rustc_span::hygiene::MacroKind; -use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan}; -use rustc_span::{Span, Symbol}; - -/// How a lint level was set. -#[derive(Clone, Copy, PartialEq, Eq, HashStable)] -pub enum LintSource { - /// Lint is at the default level as declared - /// in rustc or a plugin. - Default, - - /// Lint level was set by an attribute. - Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */), - - /// Lint level was set by a command-line flag. - CommandLine(Symbol), -} - -pub type LevelSource = (Level, LintSource); - -pub struct LintLevelSets { - pub list: Vec<LintSet>, - pub lint_cap: Level, -} - -pub enum LintSet { - CommandLine { - // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which - // flag. - specs: FxHashMap<LintId, LevelSource>, - }, - - Node { - specs: FxHashMap<LintId, LevelSource>, - parent: u32, - }, -} - -impl LintLevelSets { - pub fn new() -> Self { - LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid } - } - - pub fn get_lint_level( - &self, - lint: &'static Lint, - idx: u32, - aux: Option<&FxHashMap<LintId, LevelSource>>, - sess: &Session, - ) -> LevelSource { - let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux); - - // If `level` is none then we actually assume the default level for this - // lint. - let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition())); - - // If we're about to issue a warning, check at the last minute for any - // directives against the warnings "lint". If, for example, there's an - // `allow(warnings)` in scope then we want to respect that instead. - if level == Level::Warn { - let (warnings_level, warnings_src) = - self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux); - if let Some(configured_warning_level) = warnings_level { - if configured_warning_level != Level::Warn { - level = configured_warning_level; - src = warnings_src; - } - } - } - - // Ensure that we never exceed the `--cap-lints` argument. - level = cmp::min(level, self.lint_cap); - - if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) { - // Ensure that we never exceed driver level. - level = cmp::min(*driver_level, level); - } - - return (level, src); - } - - pub fn get_lint_id_level( - &self, - id: LintId, - mut idx: u32, - aux: Option<&FxHashMap<LintId, LevelSource>>, - ) -> (Option<Level>, LintSource) { - if let Some(specs) = aux { - if let Some(&(level, src)) = specs.get(&id) { - return (Some(level), src); - } - } - loop { - match self.list[idx as usize] { - LintSet::CommandLine { ref specs } => { - if let Some(&(level, src)) = specs.get(&id) { - return (Some(level), src); - } - return (None, LintSource::Default); - } - LintSet::Node { ref specs, parent } => { - if let Some(&(level, src)) = specs.get(&id) { - return (Some(level), src); - } - idx = parent; - } - } - } - } -} - -pub struct LintLevelMap { - pub sets: LintLevelSets, - pub id_to_set: FxHashMap<HirId, u32>, -} - -impl LintLevelMap { - /// If the `id` was previously registered with `register_id` when building - /// this `LintLevelMap` this returns the corresponding lint level and source - /// of the lint level for the lint provided. - /// - /// If the `id` was not previously registered, returns `None`. If `None` is - /// returned then the parent of `id` should be acquired and this function - /// should be called again. - pub fn level_and_source( - &self, - lint: &'static Lint, - id: HirId, - session: &Session, - ) -> Option<LevelSource> { - self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session)) - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let LintLevelMap { ref sets, ref id_to_set } = *self; - - id_to_set.hash_stable(hcx, hasher); - - let LintLevelSets { ref list, lint_cap } = *sets; - - lint_cap.hash_stable(hcx, hasher); - - hcx.while_hashing_spans(true, |hcx| { - list.len().hash_stable(hcx, hasher); - - // We are working under the assumption here that the list of - // lint-sets is built in a deterministic order. - for lint_set in list { - ::std::mem::discriminant(lint_set).hash_stable(hcx, hasher); - - match *lint_set { - LintSet::CommandLine { ref specs } => { - specs.hash_stable(hcx, hasher); - } - LintSet::Node { ref specs, parent } => { - specs.hash_stable(hcx, hasher); - parent.hash_stable(hcx, hasher); - } - } - } - }) - } -} - -pub struct LintDiagnosticBuilder<'a>(DiagnosticBuilder<'a>); - -impl<'a> LintDiagnosticBuilder<'a> { - /// Return the inner DiagnosticBuilder, first setting the primary message to `msg`. - pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a> { - self.0.set_primary_message(msg); - self.0 - } - - /// Create a LintDiagnosticBuilder from some existing DiagnosticBuilder. - pub fn new(err: DiagnosticBuilder<'a>) -> LintDiagnosticBuilder<'a> { - LintDiagnosticBuilder(err) - } -} - -pub fn struct_lint_level<'s, 'd>( - sess: &'s Session, - lint: &'static Lint, - level: Level, - src: LintSource, - span: Option<MultiSpan>, - decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd, -) { - // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to - // the "real" work. - fn struct_lint_level_impl( - sess: &'s Session, - lint: &'static Lint, - level: Level, - src: LintSource, - span: Option<MultiSpan>, - decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>, - ) { - let mut err = match (level, span) { - (Level::Allow, _) => { - return; - } - (Level::Warn, Some(span)) => sess.struct_span_warn(span, ""), - (Level::Warn, None) => sess.struct_warn(""), - (Level::Deny, Some(span)) | (Level::Forbid, Some(span)) => { - sess.struct_span_err(span, "") - } - (Level::Deny, None) | (Level::Forbid, None) => sess.struct_err(""), - }; - - // Check for future incompatibility lints and issue a stronger warning. - let lint_id = LintId::of(lint); - let future_incompatible = lint.future_incompatible; - - // If this code originates in a foreign macro, aka something that this crate - // did not itself author, then it's likely that there's nothing this crate - // can do about it. We probably want to skip the lint entirely. - if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) { - // Any suggestions made here are likely to be incorrect, so anything we - // emit shouldn't be automatically fixed by rustfix. - err.allow_suggestions(false); - - // If this is a future incompatible lint it'll become a hard error, so - // we have to emit *something*. Also allow lints to whitelist themselves - // on a case-by-case basis for emission in a foreign macro. - if future_incompatible.is_none() && !lint.report_in_external_macro { - err.cancel(); - // Don't continue further, since we don't want to have - // `diag_span_note_once` called for a diagnostic that isn't emitted. - return; - } - } - - let name = lint.name_lower(); - match src { - LintSource::Default => { - sess.diag_note_once( - &mut err, - DiagnosticMessageId::from(lint), - &format!("`#[{}({})]` on by default", level.as_str(), name), - ); - } - LintSource::CommandLine(lint_flag_val) => { - let flag = match level { - Level::Warn => "-W", - Level::Deny => "-D", - Level::Forbid => "-F", - Level::Allow => panic!(), - }; - let hyphen_case_lint_name = name.replace("_", "-"); - if lint_flag_val.as_str() == name { - sess.diag_note_once( - &mut err, - DiagnosticMessageId::from(lint), - &format!( - "requested on the command line with `{} {}`", - flag, hyphen_case_lint_name - ), - ); - } else { - let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-"); - sess.diag_note_once( - &mut err, - DiagnosticMessageId::from(lint), - &format!( - "`{} {}` implied by `{} {}`", - flag, hyphen_case_lint_name, flag, hyphen_case_flag_val - ), - ); - } - } - LintSource::Node(lint_attr_name, src, reason) => { - if let Some(rationale) = reason { - err.note(&rationale.as_str()); - } - sess.diag_span_note_once( - &mut err, - DiagnosticMessageId::from(lint), - src, - "the lint level is defined here", - ); - if lint_attr_name.as_str() != name { - let level_str = level.as_str(); - sess.diag_note_once( - &mut err, - DiagnosticMessageId::from(lint), - &format!( - "`#[{}({})]` implied by `#[{}({})]`", - level_str, name, level_str, lint_attr_name - ), - ); - } - } - } - - err.code(DiagnosticId::Lint(name)); - - if let Some(future_incompatible) = future_incompatible { - const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \ - it will become a hard error"; - - let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) { - "once this method is added to the standard library, \ - the ambiguity may cause an error or change in behavior!" - .to_owned() - } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) { - "this borrowing pattern was not meant to be accepted, \ - and may become a hard error in the future" - .to_owned() - } else if let Some(edition) = future_incompatible.edition { - format!("{} in the {} edition!", STANDARD_MESSAGE, edition) - } else { - format!("{} in a future release!", STANDARD_MESSAGE) - }; - let citation = format!("for more information, see {}", future_incompatible.reference); - err.warn(&explanation); - err.note(&citation); - } - - // Finally, run `decorate`. This function is also responsible for emitting the diagnostic. - decorate(LintDiagnosticBuilder::new(err)); - } - struct_lint_level_impl(sess, lint, level, src, span, Box::new(decorate)) -} - -/// Returns whether `span` originates in a foreign crate's external macro. -/// -/// This is used to test whether a lint should not even begin to figure out whether it should -/// be reported on the current node. -pub fn in_external_macro(sess: &Session, span: Span) -> bool { - let expn_data = span.ctxt().outer_expn_data(); - match expn_data.kind { - ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, - ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" - ExpnKind::Macro(MacroKind::Bang, _) => { - if expn_data.def_site.is_dummy() { - // Dummy span for the `def_site` means it's an external macro. - return true; - } - match sess.source_map().span_to_snippet(expn_data.def_site) { - Ok(code) => !code.starts_with("macro_rules"), - // No snippet means external macro or compiler-builtin expansion. - Err(_) => true, - } - } - ExpnKind::Macro(..) => true, // definitely a plugin - } -} - -pub fn add_elided_lifetime_in_path_suggestion( - sess: &Session, - db: &mut DiagnosticBuilder<'_>, - n: usize, - path_span: Span, - incl_angl_brckt: bool, - insertion_span: Span, - anon_lts: String, -) { - let (replace_span, suggestion) = if incl_angl_brckt { - (insertion_span, anon_lts) - } else { - // When possible, prefer a suggestion that replaces the whole - // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, ` - // at a point (which makes for an ugly/confusing label) - if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) { - // But our spans can get out of whack due to macros; if the place we think - // we want to insert `'_` isn't even within the path expression's span, we - // should bail out of making any suggestion rather than panicking on a - // subtract-with-overflow or string-slice-out-out-bounds (!) - // FIXME: can we do better? - if insertion_span.lo().0 < path_span.lo().0 { - return; - } - let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize; - if insertion_index > snippet.len() { - return; - } - let (before, after) = snippet.split_at(insertion_index); - (path_span, format!("{}{}{}", before, anon_lts, after)) - } else { - (insertion_span, anon_lts) - } - }; - db.span_suggestion( - replace_span, - &format!("indicate the anonymous lifetime{}", pluralize!(n)), - suggestion, - Applicability::MachineApplicable, - ); -} diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs deleted file mode 100644 index 88ddd96eec8..00000000000 --- a/src/librustc/macros.rs +++ /dev/null @@ -1,216 +0,0 @@ -#[macro_export] -macro_rules! bug { - () => ( bug!("impossible case reached") ); - ($($message:tt)*) => ({ - $crate::util::bug::bug_fmt(file!(), line!(), format_args!($($message)*)) - }) -} - -#[macro_export] -macro_rules! span_bug { - ($span:expr, $($message:tt)*) => ({ - $crate::util::bug::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*)) - }) -} - -/////////////////////////////////////////////////////////////////////////// -// Lift and TypeFoldable macros -// -// When possible, use one of these (relatively) convenient macros to write -// the impls for you. - -#[macro_export] -macro_rules! CloneLiftImpls { - (for <$tcx:lifetime> { $($ty:ty,)+ }) => { - $( - impl<$tcx> $crate::ty::Lift<$tcx> for $ty { - type Lifted = Self; - fn lift_to_tcx(&self, _: $crate::ty::TyCtxt<$tcx>) -> Option<Self> { - Some(Clone::clone(self)) - } - } - )+ - }; - - ($($ty:ty,)+) => { - CloneLiftImpls! { - for <'tcx> { - $($ty,)+ - } - } - }; -} - -/// Used for types that are `Copy` and which **do not care arena -/// allocated data** (i.e., don't need to be folded). -#[macro_export] -macro_rules! CloneTypeFoldableImpls { - (for <$tcx:lifetime> { $($ty:ty,)+ }) => { - $( - impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty { - fn super_fold_with<F: $crate::ty::fold::TypeFolder<$tcx>>( - &self, - _: &mut F - ) -> $ty { - Clone::clone(self) - } - - fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>( - &self, - _: &mut F) - -> bool - { - false - } - } - )+ - }; - - ($($ty:ty,)+) => { - CloneTypeFoldableImpls! { - for <'tcx> { - $($ty,)+ - } - } - }; -} - -#[macro_export] -macro_rules! CloneTypeFoldableAndLiftImpls { - ($($t:tt)*) => { - CloneTypeFoldableImpls! { $($t)* } - CloneLiftImpls! { $($t)* } - } -} - -#[macro_export] -macro_rules! EnumTypeFoldableImpl { - (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path { - $($variants:tt)* - } $(where $($wc:tt)*)*) => { - impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s - $(where $($wc)*)* - { - fn super_fold_with<V: $crate::ty::fold::TypeFolder<$tcx>>( - &self, - folder: &mut V, - ) -> Self { - EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output()) - } - - fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>( - &self, - visitor: &mut V, - ) -> bool { - EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output()) - } - } - }; - - (@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => { - match $this { - $($output)* - } - }; - - (@FoldVariants($this:expr, $folder:expr) - input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeFoldableImpl!( - @FoldVariants($this, $folder) - input($($input)*) - output( - $variant ( $($variant_arg),* ) => { - $variant ( - $($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)),* - ) - } - $($output)* - ) - ) - }; - - (@FoldVariants($this:expr, $folder:expr) - input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeFoldableImpl!( - @FoldVariants($this, $folder) - input($($input)*) - output( - $variant { $($variant_arg),* } => { - $variant { - $($variant_arg: $crate::ty::fold::TypeFoldable::fold_with( - $variant_arg, $folder - )),* } - } - $($output)* - ) - ) - }; - - (@FoldVariants($this:expr, $folder:expr) - input( ($variant:path), $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeFoldableImpl!( - @FoldVariants($this, $folder) - input($($input)*) - output( - $variant => { $variant } - $($output)* - ) - ) - }; - - (@VisitVariants($this:expr, $visitor:expr) input() output($($output:tt)*)) => { - match $this { - $($output)* - } - }; - - (@VisitVariants($this:expr, $visitor:expr) - input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeFoldableImpl!( - @VisitVariants($this, $visitor) - input($($input)*) - output( - $variant ( $($variant_arg),* ) => { - false $(|| $crate::ty::fold::TypeFoldable::visit_with( - $variant_arg, $visitor - ))* - } - $($output)* - ) - ) - }; - - (@VisitVariants($this:expr, $visitor:expr) - input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeFoldableImpl!( - @VisitVariants($this, $visitor) - input($($input)*) - output( - $variant { $($variant_arg),* } => { - false $(|| $crate::ty::fold::TypeFoldable::visit_with( - $variant_arg, $visitor - ))* - } - $($output)* - ) - ) - }; - - (@VisitVariants($this:expr, $visitor:expr) - input( ($variant:path), $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeFoldableImpl!( - @VisitVariants($this, $visitor) - input($($input)*) - output( - $variant => { false } - $($output)* - ) - ) - }; -} diff --git a/src/librustc/middle/codegen_fn_attrs.rs b/src/librustc/middle/codegen_fn_attrs.rs deleted file mode 100644 index 82adcfddc28..00000000000 --- a/src/librustc/middle/codegen_fn_attrs.rs +++ /dev/null @@ -1,124 +0,0 @@ -use crate::mir::mono::Linkage; -use rustc_attr::{InlineAttr, OptimizeAttr}; -use rustc_span::symbol::Symbol; - -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] -pub struct CodegenFnAttrs { - pub flags: CodegenFnAttrFlags, - /// Parsed representation of the `#[inline]` attribute - pub inline: InlineAttr, - /// Parsed representation of the `#[optimize]` attribute - pub optimize: OptimizeAttr, - /// The `#[export_name = "..."]` attribute, indicating a custom symbol a - /// function should be exported under - pub export_name: Option<Symbol>, - /// The `#[link_name = "..."]` attribute, indicating a custom symbol an - /// imported function should be imported as. Note that `export_name` - /// probably isn't set when this is set, this is for foreign items while - /// `#[export_name]` is for Rust-defined functions. - pub link_name: Option<Symbol>, - /// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an - /// imported function has in the dynamic library. Note that this must not - /// be set when `link_name` is set. This is for foreign items with the - /// "raw-dylib" kind. - pub link_ordinal: Option<usize>, - /// The `#[target_feature(enable = "...")]` attribute and the enabled - /// features (only enabled features are supported right now). - pub target_features: Vec<Symbol>, - /// The `#[linkage = "..."]` attribute and the value we found. - pub linkage: Option<Linkage>, - /// The `#[link_section = "..."]` attribute, or what executable section this - /// should be placed in. - pub link_section: Option<Symbol>, -} - -bitflags! { - #[derive(RustcEncodable, RustcDecodable, HashStable)] - pub struct CodegenFnAttrFlags: u32 { - /// `#[cold]`: a hint to LLVM that this function, when called, is never on - /// the hot path. - const COLD = 1 << 0; - /// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this - /// function is never null. - const ALLOCATOR = 1 << 1; - /// `#[unwind]`: an indicator that this function may unwind despite what - /// its ABI signature may otherwise imply. - const UNWIND = 1 << 2; - /// `#[rust_allocator_nounwind]`, an indicator that an imported FFI - /// function will never unwind. Probably obsolete by recent changes with - /// #[unwind], but hasn't been removed/migrated yet - const RUSTC_ALLOCATOR_NOUNWIND = 1 << 3; - /// `#[naked]`: an indicator to LLVM that no function prologue/epilogue - /// should be generated. - const NAKED = 1 << 4; - /// `#[no_mangle]`: an indicator that the function's name should be the same - /// as its symbol. - const NO_MANGLE = 1 << 5; - /// `#[rustc_std_internal_symbol]`: an indicator that this symbol is a - /// "weird symbol" for the standard library in that it has slightly - /// different linkage, visibility, and reachability rules. - const RUSTC_STD_INTERNAL_SYMBOL = 1 << 6; - /// `#[no_debug]`: an indicator that no debugging information should be - /// generated for this function by LLVM. - const NO_DEBUG = 1 << 7; - /// `#[thread_local]`: indicates a static is actually a thread local - /// piece of memory - const THREAD_LOCAL = 1 << 8; - /// `#[used]`: indicates that LLVM can't eliminate this function (but the - /// linker can!). - const USED = 1 << 9; - /// `#[ffi_returns_twice]`, indicates that an extern function can return - /// multiple times - const FFI_RETURNS_TWICE = 1 << 10; - /// `#[track_caller]`: allow access to the caller location - const TRACK_CALLER = 1 << 11; - /// `#[no_sanitize(address)]`: disables address sanitizer instrumentation - const NO_SANITIZE_ADDRESS = 1 << 12; - /// `#[no_sanitize(memory)]`: disables memory sanitizer instrumentation - const NO_SANITIZE_MEMORY = 1 << 13; - /// `#[no_sanitize(thread)]`: disables thread sanitizer instrumentation - const NO_SANITIZE_THREAD = 1 << 14; - /// All `#[no_sanitize(...)]` attributes. - const NO_SANITIZE_ANY = Self::NO_SANITIZE_ADDRESS.bits | Self::NO_SANITIZE_MEMORY.bits | Self::NO_SANITIZE_THREAD.bits; - } -} - -impl CodegenFnAttrs { - pub fn new() -> CodegenFnAttrs { - CodegenFnAttrs { - flags: CodegenFnAttrFlags::empty(), - inline: InlineAttr::None, - optimize: OptimizeAttr::None, - export_name: None, - link_name: None, - link_ordinal: None, - target_features: vec![], - linkage: None, - link_section: None, - } - } - - /// Returns `true` if `#[inline]` or `#[inline(always)]` is present. - pub fn requests_inline(&self) -> bool { - match self.inline { - InlineAttr::Hint | InlineAttr::Always => true, - InlineAttr::None | InlineAttr::Never => false, - } - } - - /// Returns `true` if it looks like this symbol needs to be exported, for example: - /// - /// * `#[no_mangle]` is present - /// * `#[export_name(...)]` is present - /// * `#[linkage]` is present - pub fn contains_extern_indicator(&self) -> bool { - self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) - || self.export_name.is_some() - || match self.linkage { - // These are private, so make sure we don't try to consider - // them external. - None | Some(Linkage::Internal) | Some(Linkage::Private) => false, - Some(_) => true, - } - } -} diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs deleted file mode 100644 index 0e7ff3a3393..00000000000 --- a/src/librustc/middle/cstore.rs +++ /dev/null @@ -1,265 +0,0 @@ -//! the rustc crate store interface. This also includes types that -//! are *mostly* used as a part of that interface, but these should -//! probably get a better home if someone can find one. - -use crate::hir::map as hir_map; -use crate::hir::map::definitions::{DefKey, DefPathTable}; -use crate::session::search_paths::PathKind; -use crate::session::CrateDisambiguator; -use crate::ty::TyCtxt; - -use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{self, MetadataRef}; -use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc_macros::HashStable; -use rustc_span::symbol::Symbol; -use rustc_span::Span; -use rustc_target::spec::Target; -use std::any::Any; -use std::path::{Path, PathBuf}; -use syntax::ast; -use syntax::expand::allocator::AllocatorKind; - -pub use self::NativeLibraryKind::*; -pub use rustc_session::utils::NativeLibraryKind; - -// lonely orphan structs and enums looking for a better home - -/// Where a crate came from on the local filesystem. One of these three options -/// must be non-None. -#[derive(PartialEq, Clone, Debug, HashStable, RustcEncodable, RustcDecodable)] -pub struct CrateSource { - pub dylib: Option<(PathBuf, PathKind)>, - pub rlib: Option<(PathBuf, PathKind)>, - pub rmeta: Option<(PathBuf, PathKind)>, -} - -impl CrateSource { - pub fn paths(&self) -> impl Iterator<Item = &PathBuf> { - self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).map(|p| &p.0) - } -} - -#[derive( - RustcEncodable, - RustcDecodable, - Copy, - Clone, - Ord, - PartialOrd, - Eq, - PartialEq, - Debug, - HashStable -)] -pub enum DepKind { - /// A dependency that is only used for its macros, none of which are visible from other crates. - /// These are included in the metadata only as placeholders and are ignored when decoding. - UnexportedMacrosOnly, - /// A dependency that is only used for its macros. - MacrosOnly, - /// A dependency that is always injected into the dependency list and so - /// doesn't need to be linked to an rlib, e.g., the injected allocator. - Implicit, - /// A dependency that is required by an rlib version of this crate. - /// Ordinary `extern crate`s result in `Explicit` dependencies. - Explicit, -} - -impl DepKind { - pub fn macros_only(self) -> bool { - match self { - DepKind::UnexportedMacrosOnly | DepKind::MacrosOnly => true, - DepKind::Implicit | DepKind::Explicit => false, - } - } -} - -#[derive(PartialEq, Clone, Debug, RustcEncodable, RustcDecodable)] -pub enum LibSource { - Some(PathBuf), - MetadataOnly, - None, -} - -impl LibSource { - pub fn is_some(&self) -> bool { - if let LibSource::Some(_) = *self { true } else { false } - } - - pub fn option(&self) -> Option<PathBuf> { - match *self { - LibSource::Some(ref p) => Some(p.clone()), - LibSource::MetadataOnly | LibSource::None => None, - } - } -} - -#[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable, HashStable)] -pub enum LinkagePreference { - RequireDynamic, - RequireStatic, -} - -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct NativeLibrary { - pub kind: NativeLibraryKind, - pub name: Option<Symbol>, - pub cfg: Option<ast::MetaItem>, - pub foreign_module: Option<DefId>, - pub wasm_import_module: Option<Symbol>, -} - -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] -pub struct ForeignModule { - pub foreign_items: Vec<DefId>, - pub def_id: DefId, -} - -#[derive(Copy, Clone, Debug, HashStable)] -pub struct ExternCrate { - pub src: ExternCrateSource, - - /// span of the extern crate that caused this to be loaded - pub span: Span, - - /// Number of links to reach the extern; - /// used to select the extern with the shortest path - pub path_len: usize, - - /// Crate that depends on this crate - pub dependency_of: CrateNum, -} - -impl ExternCrate { - /// If true, then this crate is the crate named by the extern - /// crate referenced above. If false, then this crate is a dep - /// of the crate. - pub fn is_direct(&self) -> bool { - self.dependency_of == LOCAL_CRATE - } - - pub fn rank(&self) -> impl PartialOrd { - // Prefer: - // - direct extern crate to indirect - // - shorter paths to longer - (self.is_direct(), !self.path_len) - } -} - -#[derive(Copy, Clone, Debug, HashStable)] -pub enum ExternCrateSource { - /// Crate is loaded by `extern crate`. - Extern( - /// def_id of the item in the current crate that caused - /// this crate to be loaded; note that there could be multiple - /// such ids - DefId, - ), - /// Crate is implicitly loaded by a path resolving through extern prelude. - Path, -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct EncodedMetadata { - pub raw_data: Vec<u8>, -} - -impl EncodedMetadata { - pub fn new() -> EncodedMetadata { - EncodedMetadata { raw_data: Vec::new() } - } -} - -/// The backend's way to give the crate store access to the metadata in a library. -/// Note that it returns the raw metadata bytes stored in the library file, whether -/// it is compressed, uncompressed, some weird mix, etc. -/// rmeta files are backend independent and not handled here. -/// -/// At the time of this writing, there is only one backend and one way to store -/// metadata in library -- this trait just serves to decouple rustc_metadata from -/// the archive reader, which depends on LLVM. -pub trait MetadataLoader { - fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>; - fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>; -} - -pub type MetadataLoaderDyn = dyn MetadataLoader + Sync; - -/// A store of Rust crates, through which their metadata can be accessed. -/// -/// Note that this trait should probably not be expanding today. All new -/// functionality should be driven through queries instead! -/// -/// If you find a method on this trait named `{name}_untracked` it signifies -/// that it's *not* tracked for dependency information throughout compilation -/// (it'd break incremental compilation) and should only be called pre-HIR (e.g. -/// during resolve) -pub trait CrateStore { - fn as_any(&self) -> &dyn Any; - - // resolve - fn def_key(&self, def: DefId) -> DefKey; - fn def_path(&self, def: DefId) -> hir_map::DefPath; - fn def_path_hash(&self, def: DefId) -> hir_map::DefPathHash; - fn def_path_table(&self, cnum: CrateNum) -> &DefPathTable; - - // "queries" used in resolve that aren't tracked for incremental compilation - fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol; - fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool; - fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator; - fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh; - - // This is basically a 1-based range of ints, which is a little - // silly - I may fix that. - fn crates_untracked(&self) -> Vec<CrateNum>; - - // utility functions - fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata; - fn metadata_encoding_version(&self) -> &[u8]; - fn allocator_kind(&self) -> Option<AllocatorKind>; -} - -pub type CrateStoreDyn = dyn CrateStore + sync::Sync; - -// This method is used when generating the command line to pass through to -// system linker. The linker expects undefined symbols on the left of the -// command line to be defined in libraries on the right, not the other way -// around. For more info, see some comments in the add_used_library function -// below. -// -// In order to get this left-to-right dependency ordering, we perform a -// topological sort of all crates putting the leaves at the right-most -// positions. -pub fn used_crates(tcx: TyCtxt<'_>, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)> { - let mut libs = tcx - .crates() - .iter() - .cloned() - .filter_map(|cnum| { - if tcx.dep_kind(cnum).macros_only() { - return None; - } - let source = tcx.used_crate_source(cnum); - let path = match prefer { - LinkagePreference::RequireDynamic => source.dylib.clone().map(|p| p.0), - LinkagePreference::RequireStatic => source.rlib.clone().map(|p| p.0), - }; - let path = match path { - Some(p) => LibSource::Some(p), - None => { - if source.rmeta.is_some() { - LibSource::MetadataOnly - } else { - LibSource::None - } - } - }; - Some((cnum, path)) - }) - .collect::<Vec<_>>(); - let mut ordering = tcx.postorder_cnums(LOCAL_CRATE).to_owned(); - ordering.reverse(); - libs.sort_by_cached_key(|&(a, _)| ordering.iter().position(|x| *x == a)); - libs -} diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs deleted file mode 100644 index 6ece51fe866..00000000000 --- a/src/librustc/middle/dependency_format.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! Type definitions for learning about the dependency formats of all upstream -//! crates (rlibs/dylibs/oh my). -//! -//! For all the gory details, see the provider of the `dependency_formats` -//! query. - -use crate::session::config; - -/// A list of dependencies for a certain crate type. -/// -/// The length of this vector is the same as the number of external crates used. -/// The value is None if the crate does not need to be linked (it was found -/// statically in another dylib), or Some(kind) if it needs to be linked as -/// `kind` (either static or dynamic). -pub type DependencyList = Vec<Linkage>; - -/// A mapping of all required dependencies for a particular flavor of output. -/// -/// This is local to the tcx, and is generally relevant to one session. -pub type Dependencies = Vec<(config::CrateType, DependencyList)>; - -#[derive(Copy, Clone, PartialEq, Debug, HashStable, RustcEncodable, RustcDecodable)] -pub enum Linkage { - NotLinked, - IncludedFromDylib, - Static, - Dynamic, -} diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs deleted file mode 100644 index 1f4318fa537..00000000000 --- a/src/librustc/middle/exported_symbols.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::ty::subst::SubstsRef; -use crate::ty::{self, Ty, TyCtxt}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_macros::HashStable; - -/// The SymbolExportLevel of a symbols specifies from which kinds of crates -/// the symbol will be exported. `C` symbols will be exported from any -/// kind of crate, including cdylibs which export very few things. -/// `Rust` will only be exported if the crate produced is a Rust -/// dylib. -#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)] -pub enum SymbolExportLevel { - C, - Rust, -} - -impl SymbolExportLevel { - pub fn is_below_threshold(self, threshold: SymbolExportLevel) -> bool { - threshold == SymbolExportLevel::Rust // export everything from Rust dylibs - || self == SymbolExportLevel::C - } -} - -#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)] -pub enum ExportedSymbol<'tcx> { - NonGeneric(DefId), - Generic(DefId, SubstsRef<'tcx>), - DropGlue(Ty<'tcx>), - NoDefId(ty::SymbolName), -} - -impl<'tcx> ExportedSymbol<'tcx> { - /// This is the symbol name of an instance if it is instantiated in the - /// local crate. - pub fn symbol_name_for_local_instance(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName { - match *self { - ExportedSymbol::NonGeneric(def_id) => tcx.symbol_name(ty::Instance::mono(tcx, def_id)), - ExportedSymbol::Generic(def_id, substs) => { - tcx.symbol_name(ty::Instance::new(def_id, substs)) - } - ExportedSymbol::DropGlue(ty) => { - tcx.symbol_name(ty::Instance::resolve_drop_in_place(tcx, ty)) - } - ExportedSymbol::NoDefId(symbol_name) => symbol_name, - } - } -} - -pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String { - format!( - "rust_metadata_{}_{}", - tcx.original_crate_name(LOCAL_CRATE), - tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex() - ) -} diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs deleted file mode 100644 index 62ccd946744..00000000000 --- a/src/librustc/middle/free_region.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! This module handles the relationships between "free regions", i.e., lifetime parameters. -//! Ordinarily, free regions are unrelated to one another, but they can be related via implied -//! or explicit bounds. In that case, we track the bounds using the `TransitiveRelation` type, -//! and use that to decide when one free region outlives another, and so forth. - -use crate::middle::region; -use crate::ty::free_region_map::FreeRegionMap; -use crate::ty::{Region, TyCtxt}; -use rustc_hir::def_id::DefId; - -/// Combines a `region::ScopeTree` (which governs relationships between -/// scopes) and a `FreeRegionMap` (which governs relationships between -/// free regions) to yield a complete relation between concrete -/// regions. -/// -/// This stuff is a bit convoluted and should be refactored, but as we -/// transition to NLL, it'll all go away anyhow. -pub struct RegionRelations<'a, 'tcx> { - pub tcx: TyCtxt<'tcx>, - - /// The context used to fetch the region maps. - pub context: DefId, - - /// The region maps for the given context. - pub region_scope_tree: &'a region::ScopeTree, - - /// Free-region relationships. - pub free_regions: &'a FreeRegionMap<'tcx>, -} - -impl<'a, 'tcx> RegionRelations<'a, 'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - context: DefId, - region_scope_tree: &'a region::ScopeTree, - free_regions: &'a FreeRegionMap<'tcx>, - ) -> Self { - Self { tcx, context, region_scope_tree, free_regions } - } - - pub fn lub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> Region<'tcx> { - self.free_regions.lub_free_regions(self.tcx, r_a, r_b) - } -} diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs deleted file mode 100644 index c8e284be6fc..00000000000 --- a/src/librustc/middle/lang_items.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Detecting 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. - -pub use self::LangItem::*; - -use crate::ty::{self, TyCtxt}; - -use rustc_hir::def_id::DefId; -use rustc_span::Span; -use rustc_target::spec::PanicStrategy; - -pub use rustc_hir::weak_lang_items::link_name; -pub use rustc_hir::{LangItem, LanguageItems}; - -impl<'tcx> TyCtxt<'tcx> { - /// Returns the `DefId` for a given `LangItem`. - /// If not found, fatally aborts compilation. - pub fn require_lang_item(&self, lang_item: LangItem, span: Option<Span>) -> DefId { - self.lang_items().require(lang_item).unwrap_or_else(|msg| { - if let Some(span) = span { - self.sess.span_fatal(span, &msg) - } else { - self.sess.fatal(&msg) - } - }) - } - - pub fn fn_trait_kind_from_lang_item(&self, id: DefId) -> Option<ty::ClosureKind> { - let items = self.lang_items(); - match Some(id) { - x if x == items.fn_trait() => Some(ty::ClosureKind::Fn), - x if x == items.fn_mut_trait() => Some(ty::ClosureKind::FnMut), - x if x == items.fn_once_trait() => Some(ty::ClosureKind::FnOnce), - _ => None, - } - } - - pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool { - self.lang_items().is_weak_lang_item(item_def_id) - } -} - -/// Returns `true` if the specified `lang_item` doesn't actually need to be -/// present for this compilation. -/// -/// Not all lang items are always required for each compilation, particularly in -/// the case of panic=abort. In these situations some lang items are injected by -/// crates and don't actually need to be defined in libstd. -pub fn whitelisted(tcx: TyCtxt<'_>, lang_item: LangItem) -> bool { - // If we're not compiling with unwinding, we won't actually need these - // symbols. Other panic runtimes ensure that the relevant symbols are - // available to link things together, but they're never exercised. - if tcx.sess.panic_strategy() != PanicStrategy::Unwind { - return lang_item == LangItem::EhPersonalityLangItem - || lang_item == LangItem::EhUnwindResumeLangItem; - } - - false -} diff --git a/src/librustc/middle/mod.rs b/src/librustc/middle/mod.rs deleted file mode 100644 index b20f2cf3a85..00000000000 --- a/src/librustc/middle/mod.rs +++ /dev/null @@ -1,35 +0,0 @@ -pub mod codegen_fn_attrs; -pub mod cstore; -pub mod dependency_format; -pub mod exported_symbols; -pub mod free_region; -pub mod lang_items; -pub mod lib_features { - use rustc_data_structures::fx::{FxHashMap, FxHashSet}; - use rustc_span::symbol::Symbol; - - #[derive(HashStable)] - pub struct LibFeatures { - // A map from feature to stabilisation version. - pub stable: FxHashMap<Symbol, Symbol>, - pub unstable: FxHashSet<Symbol>, - } - - impl LibFeatures { - pub fn to_vec(&self) -> Vec<(Symbol, Option<Symbol>)> { - let mut all_features: Vec<_> = self - .stable - .iter() - .map(|(f, s)| (*f, Some(*s))) - .chain(self.unstable.iter().map(|f| (*f, None))) - .collect(); - all_features.sort_unstable_by_key(|f| f.0.as_str()); - all_features - } - } -} -pub mod privacy; -pub mod recursion_limit; -pub mod region; -pub mod resolve_lifetime; -pub mod stability; diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs deleted file mode 100644 index 4756e83b5e9..00000000000 --- a/src/librustc/middle/privacy.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! A pass that checks to make sure private fields and methods aren't used -//! outside their scopes. This pass will also generate a set of exported items -//! which are available for use externally when compiled as a library. - -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::DefIdSet; -use rustc_hir::HirId; -use rustc_macros::HashStable; -use std::fmt; -use std::hash::Hash; - -// Accessibility levels, sorted in ascending order -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)] -pub enum AccessLevel { - /// Superset of `AccessLevel::Reachable` used to mark impl Trait items. - ReachableFromImplTrait, - /// Exported items + items participating in various kinds of public interfaces, - /// but not directly nameable. For example, if function `fn f() -> T {...}` is - /// public, then type `T` is reachable. Its values can be obtained by other crates - /// even if the type itself is not nameable. - Reachable, - /// Public items + items accessible to other crates with help of `pub use` re-exports - Exported, - /// Items accessible to other crates directly, without help of re-exports - Public, -} - -// Accessibility levels for reachable HIR nodes -#[derive(Clone)] -pub struct AccessLevels<Id = HirId> { - pub map: FxHashMap<Id, AccessLevel>, -} - -impl<Id: Hash + Eq> AccessLevels<Id> { - /// See `AccessLevel::Reachable`. - pub fn is_reachable(&self, id: Id) -> bool { - self.map.get(&id) >= Some(&AccessLevel::Reachable) - } - - /// See `AccessLevel::Exported`. - pub fn is_exported(&self, id: Id) -> bool { - self.map.get(&id) >= Some(&AccessLevel::Exported) - } - - /// See `AccessLevel::Public`. - pub fn is_public(&self, id: Id) -> bool { - self.map.get(&id) >= Some(&AccessLevel::Public) - } -} - -impl<Id: Hash + Eq> Default for AccessLevels<Id> { - fn default() -> Self { - AccessLevels { map: Default::default() } - } -} - -impl<Id: Hash + Eq + fmt::Debug> fmt::Debug for AccessLevels<Id> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.map, f) - } -} - -/// A set containing all exported definitions from external crates. -/// The set does not contain any entries from local crates. -pub type ExternalExports = DefIdSet; diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs deleted file mode 100644 index be530da5910..00000000000 --- a/src/librustc/middle/recursion_limit.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Recursion limit. -// -// There are various parts of the compiler that must impose arbitrary limits -// on how deeply they recurse to prevent stack overflow. Users can override -// this via an attribute on the crate like `#![recursion_limit="22"]`. This pass -// just peeks and looks for that attribute. - -use crate::session::Session; -use core::num::IntErrorKind; -use rustc::bug; -use rustc_span::symbol::{sym, Symbol}; -use syntax::ast; - -use rustc_data_structures::sync::Once; - -pub fn update_limits(sess: &Session, krate: &ast::Crate) { - update_limit(sess, krate, &sess.recursion_limit, sym::recursion_limit, 128); - update_limit(sess, krate, &sess.type_length_limit, sym::type_length_limit, 1048576); -} - -fn update_limit( - sess: &Session, - krate: &ast::Crate, - limit: &Once<usize>, - name: Symbol, - default: usize, -) { - for attr in &krate.attrs { - if !attr.check_name(name) { - continue; - } - - if let Some(s) = attr.value_str() { - match s.as_str().parse() { - Ok(n) => { - limit.set(n); - return; - } - Err(e) => { - let mut err = sess.struct_span_err( - attr.span, - "`recursion_limit` must be a non-negative integer", - ); - - let value_span = attr - .meta() - .and_then(|meta| meta.name_value_literal().cloned()) - .map(|lit| lit.span) - .unwrap_or(attr.span); - - let error_str = match e.kind() { - IntErrorKind::Overflow => "`recursion_limit` is too large", - IntErrorKind::Empty => "`recursion_limit` must be a non-negative integer", - IntErrorKind::InvalidDigit => "not a valid integer", - IntErrorKind::Underflow => bug!("`recursion_limit` should never underflow"), - IntErrorKind::Zero => bug!("zero is a valid `recursion_limit`"), - kind => bug!("unimplemented IntErrorKind variant: {:?}", kind), - }; - - err.span_label(value_span, error_str); - err.emit(); - } - } - } - } - limit.set(default); -} diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs deleted file mode 100644 index 9e9c8bd8464..00000000000 --- a/src/librustc/middle/region.rs +++ /dev/null @@ -1,669 +0,0 @@ -//! This file declares the `ScopeTree` type, which describes -//! the parent links in the region hierarchy. -//! -//! For more information about how MIR-based region-checking works, -//! see the [rustc guide]. -//! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/mir/borrowck.html - -use crate::ich::{NodeIdHashingMode, StableHashingContext}; -use crate::ty::{self, DefIdTree, TyCtxt}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_hir::Node; - -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_macros::HashStable; -use rustc_span::{Span, DUMMY_SP}; - -use std::fmt; - -/// Represents a statically-describable scope that can be used to -/// bound the lifetime/region for values. -/// -/// `Node(node_id)`: Any AST node that has any scope at all has the -/// `Node(node_id)` scope. Other variants represent special cases not -/// immediately derivable from the abstract syntax tree structure. -/// -/// `DestructionScope(node_id)` represents the scope of destructors -/// implicitly-attached to `node_id` that run immediately after the -/// expression for `node_id` itself. Not every AST node carries a -/// `DestructionScope`, but those that are `terminating_scopes` do; -/// see discussion with `ScopeTree`. -/// -/// `Remainder { block, statement_index }` represents -/// the scope of user code running immediately after the initializer -/// expression for the indexed statement, until the end of the block. -/// -/// So: the following code can be broken down into the scopes beneath: -/// -/// ```text -/// let a = f().g( 'b: { let x = d(); let y = d(); x.h(y) } ) ; -/// -/// +-+ (D12.) -/// +-+ (D11.) -/// +---------+ (R10.) -/// +-+ (D9.) -/// +----------+ (M8.) -/// +----------------------+ (R7.) -/// +-+ (D6.) -/// +----------+ (M5.) -/// +-----------------------------------+ (M4.) -/// +--------------------------------------------------+ (M3.) -/// +--+ (M2.) -/// +-----------------------------------------------------------+ (M1.) -/// -/// (M1.): Node scope of the whole `let a = ...;` statement. -/// (M2.): Node scope of the `f()` expression. -/// (M3.): Node scope of the `f().g(..)` expression. -/// (M4.): Node scope of the block labeled `'b:`. -/// (M5.): Node scope of the `let x = d();` statement -/// (D6.): DestructionScope for temporaries created during M5. -/// (R7.): Remainder scope for block `'b:`, stmt 0 (let x = ...). -/// (M8.): Node scope of the `let y = d();` statement. -/// (D9.): DestructionScope for temporaries created during M8. -/// (R10.): Remainder scope for block `'b:`, stmt 1 (let y = ...). -/// (D11.): DestructionScope for temporaries and bindings from block `'b:`. -/// (D12.): DestructionScope for temporaries created during M1 (e.g., f()). -/// ``` -/// -/// Note that while the above picture shows the destruction scopes -/// as following their corresponding node scopes, in the internal -/// data structures of the compiler the destruction scopes are -/// represented as enclosing parents. This is sound because we use the -/// enclosing parent relationship just to ensure that referenced -/// values live long enough; phrased another way, the starting point -/// of each range is not really the important thing in the above -/// picture, but rather the ending point. -// -// FIXME(pnkfelix): this currently derives `PartialOrd` and `Ord` to -// placate the same deriving in `ty::FreeRegion`, but we may want to -// actually attach a more meaningful ordering to scopes than the one -// generated via deriving here. -#[derive( - Clone, - PartialEq, - PartialOrd, - Eq, - Ord, - Hash, - Copy, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub struct Scope { - pub id: hir::ItemLocalId, - pub data: ScopeData, -} - -impl fmt::Debug for Scope { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.data { - ScopeData::Node => write!(fmt, "Node({:?})", self.id), - ScopeData::CallSite => write!(fmt, "CallSite({:?})", self.id), - ScopeData::Arguments => write!(fmt, "Arguments({:?})", self.id), - ScopeData::Destruction => write!(fmt, "Destruction({:?})", self.id), - ScopeData::Remainder(fsi) => write!( - fmt, - "Remainder {{ block: {:?}, first_statement_index: {}}}", - self.id, - fsi.as_u32(), - ), - } - } -} - -#[derive( - Clone, - PartialEq, - PartialOrd, - Eq, - Ord, - Hash, - Debug, - Copy, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub enum ScopeData { - Node, - - /// Scope of the call-site for a function or closure - /// (outlives the arguments as well as the body). - CallSite, - - /// Scope of arguments passed to a function or closure - /// (they outlive its body). - Arguments, - - /// Scope of destructors for temporaries of node-id. - Destruction, - - /// Scope following a `let id = expr;` binding in a block. - Remainder(FirstStatementIndex), -} - -rustc_index::newtype_index! { - /// Represents a subscope of `block` for a binding that is introduced - /// by `block.stmts[first_statement_index]`. Such subscopes represent - /// a suffix of the block. Note that each subscope does not include - /// the initializer expression, if any, for the statement indexed by - /// `first_statement_index`. - /// - /// For example, given `{ let (a, b) = EXPR_1; let c = EXPR_2; ... }`: - /// - /// * The subscope with `first_statement_index == 0` is scope of both - /// `a` and `b`; it does not include EXPR_1, but does include - /// everything after that first `let`. (If you want a scope that - /// includes EXPR_1 as well, then do not use `Scope::Remainder`, - /// but instead another `Scope` that encompasses the whole block, - /// e.g., `Scope::Node`. - /// - /// * The subscope with `first_statement_index == 1` is scope of `c`, - /// and thus does not include EXPR_2, but covers the `...`. - pub struct FirstStatementIndex { - derive [HashStable] - } -} - -// compilation error if size of `ScopeData` is not the same as a `u32` -static_assert_size!(ScopeData, 4); - -impl Scope { - /// Returns a item-local ID associated with this scope. - /// - /// N.B., likely to be replaced as API is refined; e.g., pnkfelix - /// anticipates `fn entry_node_id` and `fn each_exit_node_id`. - pub fn item_local_id(&self) -> hir::ItemLocalId { - self.id - } - - pub fn hir_id(&self, scope_tree: &ScopeTree) -> hir::HirId { - match scope_tree.root_body { - Some(hir_id) => hir::HirId { owner: hir_id.owner, local_id: self.item_local_id() }, - None => hir::DUMMY_HIR_ID, - } - } - - /// Returns the span of this `Scope`. Note that in general the - /// returned span may not correspond to the span of any `NodeId` in - /// the AST. - pub fn span(&self, tcx: TyCtxt<'_>, scope_tree: &ScopeTree) -> Span { - let hir_id = self.hir_id(scope_tree); - if hir_id == hir::DUMMY_HIR_ID { - return DUMMY_SP; - } - let span = tcx.hir().span(hir_id); - if let ScopeData::Remainder(first_statement_index) = self.data { - if let Node::Block(ref blk) = tcx.hir().get(hir_id) { - // Want span for scope starting after the - // indexed statement and ending at end of - // `blk`; reuse span of `blk` and shift `lo` - // forward to end of indexed statement. - // - // (This is the special case aluded to in the - // doc-comment for this method) - - let stmt_span = blk.stmts[first_statement_index.index()].span; - - // To avoid issues with macro-generated spans, the span - // of the statement must be nested in that of the block. - if span.lo() <= stmt_span.lo() && stmt_span.lo() <= span.hi() { - return Span::new(stmt_span.lo(), span.hi(), span.ctxt()); - } - } - } - span - } -} - -pub type ScopeDepth = u32; - -/// The region scope tree encodes information about region relationships. -#[derive(Default, Debug)] -pub struct ScopeTree { - /// If not empty, this body is the root of this region hierarchy. - pub root_body: Option<hir::HirId>, - - /// The parent of the root body owner, if the latter is an - /// an associated const or method, as impls/traits can also - /// have lifetime parameters free in this body. - pub root_parent: Option<hir::HirId>, - - /// Maps from a scope ID to the enclosing scope id; - /// this is usually corresponding to the lexical nesting, though - /// in the case of closures the parent scope is the innermost - /// conditional expression or repeating block. (Note that the - /// enclosing scope ID for the block associated with a closure is - /// the closure itself.) - pub parent_map: FxHashMap<Scope, (Scope, ScopeDepth)>, - - /// Maps from a variable or binding ID to the block in which that - /// variable is declared. - var_map: FxHashMap<hir::ItemLocalId, Scope>, - - /// Maps from a `NodeId` to the associated destruction scope (if any). - destruction_scopes: FxHashMap<hir::ItemLocalId, Scope>, - - /// `rvalue_scopes` includes entries for those expressions whose - /// cleanup scope is larger than the default. The map goes from the - /// expression ID to the cleanup scope id. For rvalues not present in - /// this table, the appropriate cleanup scope is the innermost - /// enclosing statement, conditional expression, or repeating - /// block (see `terminating_scopes`). - /// In constants, None is used to indicate that certain expressions - /// escape into 'static and should have no local cleanup scope. - rvalue_scopes: FxHashMap<hir::ItemLocalId, Option<Scope>>, - - /// Encodes the hierarchy of fn bodies. Every fn body (including - /// closures) forms its own distinct region hierarchy, rooted in - /// the block that is the fn body. This map points from the ID of - /// that root block to the ID of the root block for the enclosing - /// fn, if any. Thus the map structures the fn bodies into a - /// hierarchy based on their lexical mapping. This is used to - /// handle the relationships between regions in a fn and in a - /// closure defined by that fn. See the "Modeling closures" - /// section of the README in infer::region_constraints for - /// more details. - closure_tree: FxHashMap<hir::ItemLocalId, hir::ItemLocalId>, - - /// If there are any `yield` nested within a scope, this map - /// stores the `Span` of the last one and its index in the - /// postorder of the Visitor traversal on the HIR. - /// - /// HIR Visitor postorder indexes might seem like a peculiar - /// thing to care about. but it turns out that HIR bindings - /// and the temporary results of HIR expressions are never - /// storage-live at the end of HIR nodes with postorder indexes - /// lower than theirs, and therefore don't need to be suspended - /// at yield-points at these indexes. - /// - /// For an example, suppose we have some code such as: - /// ```rust,ignore (example) - /// foo(f(), yield y, bar(g())) - /// ``` - /// - /// With the HIR tree (calls numbered for expository purposes) - /// ``` - /// Call#0(foo, [Call#1(f), Yield(y), Call#2(bar, Call#3(g))]) - /// ``` - /// - /// Obviously, the result of `f()` was created before the yield - /// (and therefore needs to be kept valid over the yield) while - /// the result of `g()` occurs after the yield (and therefore - /// doesn't). If we want to infer that, we can look at the - /// postorder traversal: - /// ```plain,ignore - /// `foo` `f` Call#1 `y` Yield `bar` `g` Call#3 Call#2 Call#0 - /// ``` - /// - /// In which we can easily see that `Call#1` occurs before the yield, - /// and `Call#3` after it. - /// - /// To see that this method works, consider: - /// - /// Let `D` be our binding/temporary and `U` be our other HIR node, with - /// `HIR-postorder(U) < HIR-postorder(D)` (in our example, U would be - /// the yield and D would be one of the calls). Let's show that - /// `D` is storage-dead at `U`. - /// - /// Remember that storage-live/storage-dead refers to the state of - /// the *storage*, and does not consider moves/drop flags. - /// - /// Then: - /// 1. From the ordering guarantee of HIR visitors (see - /// `rustc::hir::intravisit`), `D` does not dominate `U`. - /// 2. Therefore, `D` is *potentially* storage-dead at `U` (because - /// we might visit `U` without ever getting to `D`). - /// 3. However, we guarantee that at each HIR point, each - /// binding/temporary is always either always storage-live - /// or always storage-dead. This is what is being guaranteed - /// by `terminating_scopes` including all blocks where the - /// count of executions is not guaranteed. - /// 4. By `2.` and `3.`, `D` is *statically* storage-dead at `U`, - /// QED. - /// - /// This property ought to not on (3) in an essential way -- it - /// is probably still correct even if we have "unrestricted" terminating - /// scopes. However, why use the complicated proof when a simple one - /// works? - /// - /// A subtle thing: `box` expressions, such as `box (&x, yield 2, &y)`. It - /// might seem that a `box` expression creates a `Box<T>` temporary - /// when it *starts* executing, at `HIR-preorder(BOX-EXPR)`. That might - /// be true in the MIR desugaring, but it is not important in the semantics. - /// - /// The reason is that semantically, until the `box` expression returns, - /// the values are still owned by their containing expressions. So - /// we'll see that `&x`. - pub yield_in_scope: FxHashMap<Scope, YieldData>, - - /// The number of visit_expr and visit_pat calls done in the body. - /// Used to sanity check visit_expr/visit_pat call count when - /// calculating generator interiors. - pub body_expr_count: FxHashMap<hir::BodyId, usize>, -} - -#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)] -pub struct YieldData { - /// The `Span` of the yield. - pub span: Span, - /// The number of expressions and patterns appearing before the `yield` in the body plus one. - pub expr_and_pat_count: usize, - pub source: hir::YieldSource, -} - -impl<'tcx> ScopeTree { - pub fn record_scope_parent(&mut self, child: Scope, parent: Option<(Scope, ScopeDepth)>) { - debug!("{:?}.parent = {:?}", child, parent); - - if let Some(p) = parent { - let prev = self.parent_map.insert(child, p); - assert!(prev.is_none()); - } - - // Record the destruction scopes for later so we can query them. - if let ScopeData::Destruction = child.data { - self.destruction_scopes.insert(child.item_local_id(), child); - } - } - - pub fn each_encl_scope<E>(&self, mut e: E) - where - E: FnMut(Scope, Scope), - { - for (&child, &parent) in &self.parent_map { - e(child, parent.0) - } - } - - pub fn each_var_scope<E>(&self, mut e: E) - where - E: FnMut(&hir::ItemLocalId, Scope), - { - for (child, &parent) in self.var_map.iter() { - e(child, parent) - } - } - - pub fn opt_destruction_scope(&self, n: hir::ItemLocalId) -> Option<Scope> { - self.destruction_scopes.get(&n).cloned() - } - - /// Records that `sub_closure` is defined within `sup_closure`. These IDs - /// should be the ID of the block that is the fn body, which is - /// also the root of the region hierarchy for that fn. - pub fn record_closure_parent( - &mut self, - sub_closure: hir::ItemLocalId, - sup_closure: hir::ItemLocalId, - ) { - debug!( - "record_closure_parent(sub_closure={:?}, sup_closure={:?})", - sub_closure, sup_closure - ); - assert!(sub_closure != sup_closure); - let previous = self.closure_tree.insert(sub_closure, sup_closure); - assert!(previous.is_none()); - } - - pub fn record_var_scope(&mut self, var: hir::ItemLocalId, lifetime: Scope) { - debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime); - assert!(var != lifetime.item_local_id()); - self.var_map.insert(var, lifetime); - } - - pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) { - debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime); - if let Some(lifetime) = lifetime { - assert!(var != lifetime.item_local_id()); - } - self.rvalue_scopes.insert(var, lifetime); - } - - /// Returns the narrowest scope that encloses `id`, if any. - pub fn opt_encl_scope(&self, id: Scope) -> Option<Scope> { - self.parent_map.get(&id).cloned().map(|(p, _)| p) - } - - /// Returns the narrowest scope that encloses `id`, if any. - #[allow(dead_code)] // used in cfg - pub fn encl_scope(&self, id: Scope) -> Scope { - self.opt_encl_scope(id).unwrap() - } - - /// Returns the lifetime of the local variable `var_id` - pub fn var_scope(&self, var_id: hir::ItemLocalId) -> Scope { - self.var_map - .get(&var_id) - .cloned() - .unwrap_or_else(|| bug!("no enclosing scope for id {:?}", var_id)) - } - - /// Returns the scope when the temp created by `expr_id` will be cleaned up. - pub fn temporary_scope(&self, expr_id: hir::ItemLocalId) -> Option<Scope> { - // Check for a designated rvalue scope. - if let Some(&s) = self.rvalue_scopes.get(&expr_id) { - debug!("temporary_scope({:?}) = {:?} [custom]", expr_id, s); - return s; - } - - // Otherwise, locate the innermost terminating scope - // if there's one. Static items, for instance, won't - // have an enclosing scope, hence no scope will be - // returned. - let mut id = Scope { id: expr_id, data: ScopeData::Node }; - - while let Some(&(p, _)) = self.parent_map.get(&id) { - match p.data { - ScopeData::Destruction => { - debug!("temporary_scope({:?}) = {:?} [enclosing]", expr_id, id); - return Some(id); - } - _ => id = p, - } - } - - debug!("temporary_scope({:?}) = None", expr_id); - return None; - } - - /// Returns the lifetime of the variable `id`. - pub fn var_region(&self, id: hir::ItemLocalId) -> ty::RegionKind { - let scope = ty::ReScope(self.var_scope(id)); - debug!("var_region({:?}) = {:?}", id, scope); - scope - } - - pub fn scopes_intersect(&self, scope1: Scope, scope2: Scope) -> bool { - self.is_subscope_of(scope1, scope2) || self.is_subscope_of(scope2, scope1) - } - - /// Returns `true` if `subscope` is equal to or is lexically nested inside `superscope`, and - /// `false` otherwise. - pub fn is_subscope_of(&self, subscope: Scope, superscope: Scope) -> bool { - let mut s = subscope; - debug!("is_subscope_of({:?}, {:?})", subscope, superscope); - while superscope != s { - match self.opt_encl_scope(s) { - None => { - debug!("is_subscope_of({:?}, {:?}, s={:?})=false", subscope, superscope, s); - return false; - } - Some(scope) => s = scope, - } - } - - debug!("is_subscope_of({:?}, {:?})=true", subscope, superscope); - - return true; - } - - /// Returns the ID of the innermost containing body. - pub fn containing_body(&self, mut scope: Scope) -> Option<hir::ItemLocalId> { - loop { - if let ScopeData::CallSite = scope.data { - return Some(scope.item_local_id()); - } - - scope = self.opt_encl_scope(scope)?; - } - } - - /// Finds the nearest common ancestor of two scopes. That is, finds the - /// smallest scope which is greater than or equal to both `scope_a` and - /// `scope_b`. - pub fn nearest_common_ancestor(&self, scope_a: Scope, scope_b: Scope) -> Scope { - if scope_a == scope_b { - return scope_a; - } - - let mut a = scope_a; - let mut b = scope_b; - - // Get the depth of each scope's parent. If either scope has no parent, - // it must be the root, which means we can stop immediately because the - // root must be the nearest common ancestor. (In practice, this is - // moderately common.) - let (parent_a, parent_a_depth) = match self.parent_map.get(&a) { - Some(pd) => *pd, - None => return a, - }; - let (parent_b, parent_b_depth) = match self.parent_map.get(&b) { - Some(pd) => *pd, - None => return b, - }; - - if parent_a_depth > parent_b_depth { - // `a` is lower than `b`. Move `a` up until it's at the same depth - // as `b`. The first move up is trivial because we already found - // `parent_a` above; the loop does the remaining N-1 moves. - a = parent_a; - for _ in 0..(parent_a_depth - parent_b_depth - 1) { - a = self.parent_map.get(&a).unwrap().0; - } - } else if parent_b_depth > parent_a_depth { - // `b` is lower than `a`. - b = parent_b; - for _ in 0..(parent_b_depth - parent_a_depth - 1) { - b = self.parent_map.get(&b).unwrap().0; - } - } else { - // Both scopes are at the same depth, and we know they're not equal - // because that case was tested for at the top of this function. So - // we can trivially move them both up one level now. - assert!(parent_a_depth != 0); - a = parent_a; - b = parent_b; - } - - // Now both scopes are at the same level. We move upwards in lockstep - // until they match. In practice, this loop is almost always executed - // zero times because `a` is almost always a direct ancestor of `b` or - // vice versa. - while a != b { - a = self.parent_map.get(&a).unwrap().0; - b = self.parent_map.get(&b).unwrap().0; - } - - a - } - - /// Assuming that the provided region was defined within this `ScopeTree`, - /// returns the outermost `Scope` that the region outlives. - pub fn early_free_scope(&self, tcx: TyCtxt<'tcx>, br: &ty::EarlyBoundRegion) -> Scope { - let param_owner = tcx.parent(br.def_id).unwrap(); - - let param_owner_id = tcx.hir().as_local_hir_id(param_owner).unwrap(); - let scope = tcx - .hir() - .maybe_body_owned_by(param_owner_id) - .map(|body_id| tcx.hir().body(body_id).value.hir_id.local_id) - .unwrap_or_else(|| { - // The lifetime was defined on node that doesn't own a body, - // which in practice can only mean a trait or an impl, that - // is the parent of a method, and that is enforced below. - if Some(param_owner_id) != self.root_parent { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "free_scope: {:?} not recognized by the \ - region scope tree for {:?} / {:?}", - param_owner, - self.root_parent.map(|id| tcx.hir().local_def_id(id)), - self.root_body.map(|hir_id| DefId::local(hir_id.owner)) - ), - ); - } - - // The trait/impl lifetime is in scope for the method's body. - self.root_body.unwrap().local_id - }); - - Scope { id: scope, data: ScopeData::CallSite } - } - - /// Assuming that the provided region was defined within this `ScopeTree`, - /// returns the outermost `Scope` that the region outlives. - pub fn free_scope(&self, tcx: TyCtxt<'tcx>, fr: &ty::FreeRegion) -> Scope { - let param_owner = match fr.bound_region { - ty::BoundRegion::BrNamed(def_id, _) => tcx.parent(def_id).unwrap(), - _ => fr.scope, - }; - - // Ensure that the named late-bound lifetimes were defined - // on the same function that they ended up being freed in. - assert_eq!(param_owner, fr.scope); - - let param_owner_id = tcx.hir().as_local_hir_id(param_owner).unwrap(); - let body_id = tcx.hir().body_owned_by(param_owner_id); - Scope { id: tcx.hir().body(body_id).value.hir_id.local_id, data: ScopeData::CallSite } - } - - /// Checks whether the given scope contains a `yield`. If so, - /// returns `Some((span, expr_count))` with the span of a yield we found and - /// the number of expressions and patterns appearing before the `yield` in the body + 1. - /// If there a are multiple yields in a scope, the one with the highest number is returned. - pub fn yield_in_scope(&self, scope: Scope) -> Option<YieldData> { - self.yield_in_scope.get(&scope).cloned() - } - - /// Gives the number of expressions visited in a body. - /// Used to sanity check visit_expr call count when - /// calculating generator interiors. - pub fn body_expr_count(&self, body_id: hir::BodyId) -> Option<usize> { - self.body_expr_count.get(&body_id).map(|r| *r) - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let ScopeTree { - root_body, - root_parent, - ref body_expr_count, - ref parent_map, - ref var_map, - ref destruction_scopes, - ref rvalue_scopes, - ref closure_tree, - ref yield_in_scope, - } = *self; - - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - root_body.hash_stable(hcx, hasher); - root_parent.hash_stable(hcx, hasher); - }); - - body_expr_count.hash_stable(hcx, hasher); - parent_map.hash_stable(hcx, hasher); - var_map.hash_stable(hcx, hasher); - destruction_scopes.hash_stable(hcx, hasher); - rvalue_scopes.hash_stable(hcx, hasher); - closure_tree.hash_stable(hcx, hasher); - yield_in_scope.hash_stable(hcx, hasher); - } -} diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs deleted file mode 100644 index c21ba1b3bd2..00000000000 --- a/src/librustc/middle/resolve_lifetime.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! Name resolution for lifetimes: type declarations. - -use crate::ty; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{GenericParam, ItemLocalId}; -use rustc_hir::{GenericParamKind, LifetimeParamKind}; -use rustc_macros::HashStable; - -/// The origin of a named lifetime definition. -/// -/// This is used to prevent the usage of in-band lifetimes in `Fn`/`fn` syntax. -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, HashStable)] -pub enum LifetimeDefOrigin { - // Explicit binders like `fn foo<'a>(x: &'a u8)` or elided like `impl Foo<&u32>` - ExplicitOrElided, - // In-band declarations like `fn foo(x: &'a u8)` - InBand, - // Some kind of erroneous origin - Error, -} - -impl LifetimeDefOrigin { - pub fn from_param(param: &GenericParam<'_>) -> Self { - match param.kind { - GenericParamKind::Lifetime { kind } => match kind { - LifetimeParamKind::InBand => LifetimeDefOrigin::InBand, - LifetimeParamKind::Explicit => LifetimeDefOrigin::ExplicitOrElided, - LifetimeParamKind::Elided => LifetimeDefOrigin::ExplicitOrElided, - LifetimeParamKind::Error => LifetimeDefOrigin::Error, - }, - _ => bug!("expected a lifetime param"), - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, HashStable)] -pub enum Region { - Static, - EarlyBound(/* index */ u32, /* lifetime decl */ DefId, LifetimeDefOrigin), - LateBound(ty::DebruijnIndex, /* lifetime decl */ DefId, LifetimeDefOrigin), - LateBoundAnon(ty::DebruijnIndex, /* anon index */ u32), - Free(DefId, /* lifetime decl */ DefId), -} - -/// A set containing, at most, one known element. -/// If two distinct values are inserted into a set, then it -/// becomes `Many`, which can be used to detect ambiguities. -#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug, HashStable)] -pub enum Set1<T> { - Empty, - One(T), - Many, -} - -impl<T: PartialEq> Set1<T> { - pub fn insert(&mut self, value: T) { - *self = match self { - Set1::Empty => Set1::One(value), - Set1::One(old) if *old == value => return, - _ => Set1::Many, - }; - } -} - -pub type ObjectLifetimeDefault = Set1<Region>; - -/// Maps the id of each lifetime reference to the lifetime decl -/// that it corresponds to. -#[derive(Default, HashStable)] -pub struct ResolveLifetimes { - /// Maps from every use of a named (not anonymous) lifetime to a - /// `Region` describing how that region is bound - pub defs: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Region>>, - - /// Set of lifetime def ids that are late-bound; a region can - /// be late-bound if (a) it does NOT appear in a where-clause and - /// (b) it DOES appear in the arguments. - pub late_bound: FxHashMap<LocalDefId, FxHashSet<ItemLocalId>>, - - /// For each type and trait definition, maps type parameters - /// to the trait object lifetime defaults computed from them. - pub object_lifetime_defaults: - FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Vec<ObjectLifetimeDefault>>>, -} diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs deleted file mode 100644 index 7b5faa2423a..00000000000 --- a/src/librustc/middle/stability.rs +++ /dev/null @@ -1,413 +0,0 @@ -//! A pass that annotates every item and method with its stability level, -//! propagating default levels lexically from parent to children ast nodes. - -pub use self::StabilityLevel::*; - -use crate::session::{DiagnosticMessageId, Session}; -use crate::ty::{self, TyCtxt}; -use rustc_attr::{self as attr, ConstStability, Deprecation, RustcDeprecation, Stability}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_feature::GateIssue; -use rustc_hir as hir; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; -use rustc_hir::{self, HirId}; -use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; -use rustc_session::lint::{BuiltinLintDiagnostics, Lint, LintBuffer}; -use rustc_session::parse::feature_err_issue; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{MultiSpan, Span}; -use syntax::ast::CRATE_NODE_ID; - -use std::num::NonZeroU32; - -#[derive(PartialEq, Clone, Copy, Debug)] -pub enum StabilityLevel { - Unstable, - Stable, -} - -impl StabilityLevel { - pub fn from_attr_level(level: &attr::StabilityLevel) -> Self { - if level.is_stable() { Stable } else { Unstable } - } -} - -/// An entry in the `depr_map`. -#[derive(Clone, HashStable)] -pub struct DeprecationEntry { - /// The metadata of the attribute associated with this entry. - pub attr: Deprecation, - /// The `DefId` where the attr was originally attached. `None` for non-local - /// `DefId`'s. - origin: Option<HirId>, -} - -impl DeprecationEntry { - pub fn local(attr: Deprecation, id: HirId) -> DeprecationEntry { - DeprecationEntry { attr, origin: Some(id) } - } - - pub fn external(attr: Deprecation) -> DeprecationEntry { - DeprecationEntry { attr, origin: None } - } - - pub fn same_origin(&self, other: &DeprecationEntry) -> bool { - match (self.origin, other.origin) { - (Some(o1), Some(o2)) => o1 == o2, - _ => false, - } - } -} - -/// A stability index, giving the stability level for items and methods. -#[derive(HashStable)] -pub struct Index<'tcx> { - /// This is mostly a cache, except the stabilities of local items - /// are filled by the annotator. - pub stab_map: FxHashMap<HirId, &'tcx Stability>, - pub const_stab_map: FxHashMap<HirId, &'tcx ConstStability>, - pub depr_map: FxHashMap<HirId, DeprecationEntry>, - - /// Maps for each crate whether it is part of the staged API. - pub staged_api: FxHashMap<CrateNum, bool>, - - /// Features enabled for this crate. - pub active_features: FxHashSet<Symbol>, -} - -impl<'tcx> Index<'tcx> { - pub fn local_stability(&self, id: HirId) -> Option<&'tcx Stability> { - self.stab_map.get(&id).cloned() - } - - pub fn local_const_stability(&self, id: HirId) -> Option<&'tcx ConstStability> { - self.const_stab_map.get(&id).cloned() - } - - pub fn local_deprecation_entry(&self, id: HirId) -> Option<DeprecationEntry> { - self.depr_map.get(&id).cloned() - } -} - -pub fn report_unstable( - sess: &Session, - feature: Symbol, - reason: Option<Symbol>, - issue: Option<NonZeroU32>, - is_soft: bool, - span: Span, - soft_handler: impl FnOnce(&'static Lint, Span, &str), -) { - let msg = match reason { - Some(r) => format!("use of unstable library feature '{}': {}", feature, r), - None => format!("use of unstable library feature '{}'", &feature), - }; - - let msp: MultiSpan = span.into(); - let sm = &sess.parse_sess.source_map(); - let span_key = msp.primary_span().and_then(|sp: Span| { - if !sp.is_dummy() { - let file = sm.lookup_char_pos(sp.lo()).file; - if file.name.is_macros() { None } else { Some(span) } - } else { - None - } - }); - - let error_id = (DiagnosticMessageId::StabilityId(issue), span_key, msg.clone()); - let fresh = sess.one_time_diagnostics.borrow_mut().insert(error_id); - if fresh { - if is_soft { - soft_handler(SOFT_UNSTABLE, span, &msg) - } else { - feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg) - .emit(); - } - } -} - -/// Checks whether an item marked with `deprecated(since="X")` is currently -/// deprecated (i.e., whether X is not greater than the current rustc version). -pub fn deprecation_in_effect(since: &str) -> bool { - fn parse_version(ver: &str) -> Vec<u32> { - // We ignore non-integer components of the version (e.g., "nightly"). - ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect() - } - - if let Some(rustc) = option_env!("CFG_RELEASE") { - let since: Vec<u32> = parse_version(since); - let rustc: Vec<u32> = parse_version(rustc); - // We simply treat invalid `since` attributes as relating to a previous - // Rust version, thus always displaying the warning. - if since.len() != 3 { - return true; - } - since <= rustc - } else { - // By default, a deprecation warning applies to - // the current version of the compiler. - true - } -} - -pub fn deprecation_suggestion( - diag: &mut DiagnosticBuilder<'_>, - suggestion: Option<Symbol>, - span: Span, -) { - if let Some(suggestion) = suggestion { - diag.span_suggestion( - span, - "replace the use of the deprecated item", - suggestion.to_string(), - Applicability::MachineApplicable, - ); - } -} - -fn deprecation_message_common(message: String, reason: Option<Symbol>) -> String { - match reason { - Some(reason) => format!("{}: {}", message, reason), - None => message, - } -} - -pub fn deprecation_message(depr: &Deprecation, path: &str) -> (String, &'static Lint) { - let message = format!("use of deprecated item '{}'", path); - (deprecation_message_common(message, depr.note), DEPRECATED) -} - -pub fn rustc_deprecation_message(depr: &RustcDeprecation, path: &str) -> (String, &'static Lint) { - let (message, lint) = if deprecation_in_effect(&depr.since.as_str()) { - (format!("use of deprecated item '{}'", path), DEPRECATED) - } else { - ( - format!( - "use of item '{}' that will be deprecated in future version {}", - path, depr.since - ), - DEPRECATED_IN_FUTURE, - ) - }; - (deprecation_message_common(message, Some(depr.reason)), lint) -} - -pub fn early_report_deprecation( - lint_buffer: &'a mut LintBuffer, - message: &str, - suggestion: Option<Symbol>, - lint: &'static Lint, - span: Span, -) { - if span.in_derive_expansion() { - return; - } - - let diag = BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span); - lint_buffer.buffer_lint_with_diagnostic(lint, CRATE_NODE_ID, span, message, diag); -} - -fn late_report_deprecation( - tcx: TyCtxt<'_>, - message: &str, - suggestion: Option<Symbol>, - lint: &'static Lint, - span: Span, - def_id: DefId, - hir_id: HirId, -) { - if span.in_derive_expansion() { - return; - } - - tcx.struct_span_lint_hir(lint, hir_id, span, |lint| { - let mut diag = lint.build(message); - if let hir::Node::Expr(_) = tcx.hir().get(hir_id) { - deprecation_suggestion(&mut diag, suggestion, span); - } - diag.emit() - }); - if hir_id == hir::DUMMY_HIR_ID { - span_bug!(span, "emitted a {} lint with dummy HIR id: {:?}", lint.name, def_id); - } -} - -/// Result of `TyCtxt::eval_stability`. -pub enum EvalResult { - /// We can use the item because it is stable or we provided the - /// corresponding feature gate. - Allow, - /// We cannot use the item because it is unstable and we did not provide the - /// corresponding feature gate. - Deny { feature: Symbol, reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool }, - /// The item does not have the `#[stable]` or `#[unstable]` marker assigned. - Unmarked, -} - -// See issue #38412. -fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, mut def_id: DefId) -> bool { - // Check if `def_id` is a trait method. - match tcx.def_kind(def_id) { - Some(DefKind::Method) | Some(DefKind::AssocTy) | Some(DefKind::AssocConst) => { - if let ty::TraitContainer(trait_def_id) = tcx.associated_item(def_id).container { - // Trait methods do not declare visibility (even - // for visibility info in cstore). Use containing - // trait instead, so methods of `pub` traits are - // themselves considered `pub`. - def_id = trait_def_id; - } - } - _ => {} - } - - let visibility = tcx.visibility(def_id); - - match visibility { - // Must check stability for `pub` items. - ty::Visibility::Public => false, - - // These are not visible outside crate; therefore - // stability markers are irrelevant, if even present. - ty::Visibility::Restricted(..) | ty::Visibility::Invisible => true, - } -} - -impl<'tcx> TyCtxt<'tcx> { - /// Evaluates the stability of an item. - /// - /// Returns `EvalResult::Allow` if the item is stable, or unstable but the corresponding - /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending - /// unstable feature otherwise. - /// - /// If `id` is `Some(_)`, this function will also check if the item at `def_id` has been - /// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to - /// `id`. - pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> EvalResult { - // Deprecated attributes apply in-crate and cross-crate. - if let Some(id) = id { - if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) { - let parent_def_id = self.hir().local_def_id(self.hir().get_parent_item(id)); - let skip = self - .lookup_deprecation_entry(parent_def_id) - .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry)); - - if !skip { - let (message, lint) = - deprecation_message(&depr_entry.attr, &self.def_path_str(def_id)); - late_report_deprecation(self, &message, None, lint, span, def_id, id); - } - }; - } - - let is_staged_api = - self.lookup_stability(DefId { index: CRATE_DEF_INDEX, ..def_id }).is_some(); - if !is_staged_api { - return EvalResult::Allow; - } - - let stability = self.lookup_stability(def_id); - debug!( - "stability: \ - inspecting def_id={:?} span={:?} of stability={:?}", - def_id, span, stability - ); - - if let Some(id) = id { - if let Some(stability) = stability { - if let Some(depr) = &stability.rustc_depr { - let (message, lint) = - rustc_deprecation_message(depr, &self.def_path_str(def_id)); - late_report_deprecation( - self, - &message, - depr.suggestion, - lint, - span, - def_id, - id, - ); - } - } - } - - // Only the cross-crate scenario matters when checking unstable APIs - let cross_crate = !def_id.is_local(); - if !cross_crate { - return EvalResult::Allow; - } - - // Issue #38412: private items lack stability markers. - if skip_stability_check_due_to_privacy(self, def_id) { - return EvalResult::Allow; - } - - match stability { - Some(&Stability { - level: attr::Unstable { reason, issue, is_soft }, feature, .. - }) => { - if span.allows_unstable(feature) { - debug!("stability: skipping span={:?} since it is internal", span); - return EvalResult::Allow; - } - if self.stability().active_features.contains(&feature) { - return EvalResult::Allow; - } - - // When we're compiling the compiler itself we may pull in - // crates from crates.io, but those crates may depend on other - // crates also pulled in from crates.io. We want to ideally be - // able to compile everything without requiring upstream - // modifications, so in the case that this looks like a - // `rustc_private` crate (e.g., a compiler crate) and we also have - // the `-Z force-unstable-if-unmarked` flag present (we're - // compiling a compiler crate), then let this missing feature - // annotation slide. - if feature == sym::rustc_private && issue == NonZeroU32::new(27812) { - if self.sess.opts.debugging_opts.force_unstable_if_unmarked { - return EvalResult::Allow; - } - } - - EvalResult::Deny { feature, reason, issue, is_soft } - } - Some(_) => { - // Stable APIs are always ok to call and deprecated APIs are - // handled by the lint emitting logic above. - EvalResult::Allow - } - None => EvalResult::Unmarked, - } - } - - /// Checks if an item is stable or error out. - /// - /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not - /// exist, emits an error. - /// - /// Additionally, this function will also check if the item is deprecated. If so, and `id` is - /// not `None`, a deprecated lint attached to `id` will be emitted. - pub fn check_stability(self, def_id: DefId, id: Option<HirId>, span: Span) { - let soft_handler = |lint, span, msg: &_| { - self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| { - lint.build(msg).emit() - }) - }; - match self.eval_stability(def_id, id, span) { - EvalResult::Allow => {} - EvalResult::Deny { feature, reason, issue, is_soft } => { - report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler) - } - EvalResult::Unmarked => { - // The API could be uncallable for other reasons, for example when a private module - // was referenced. - self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id)); - } - } - } - - pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> { - self.lookup_deprecation_entry(id).map(|depr| depr.attr) - } -} diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs deleted file mode 100644 index 00ecc7a7a0a..00000000000 --- a/src/librustc/mir/cache.rs +++ /dev/null @@ -1,271 +0,0 @@ -use crate::ich::StableHashingContext; -use crate::mir::{BasicBlock, BasicBlockData, Body, LocalDecls, Location, Successors}; -use rustc_data_structures::graph::dominators::{dominators, Dominators}; -use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_index::vec::IndexVec; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use std::iter; -use std::ops::{Deref, DerefMut, Index, IndexMut}; -use std::vec::IntoIter; - -#[derive(Clone, Debug)] -pub struct Cache { - predecessors: Option<IndexVec<BasicBlock, Vec<BasicBlock>>>, -} - -impl rustc_serialize::Encodable for Cache { - fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { - Encodable::encode(&(), s) - } -} - -impl rustc_serialize::Decodable for Cache { - fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> { - Decodable::decode(d).map(|_v: ()| Self::new()) - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for Cache { - fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) { - // Do nothing. - } -} - -impl Cache { - pub fn new() -> Self { - Self { predecessors: None } - } - - pub fn invalidate_predecessors(&mut self) { - // FIXME: consider being more fine-grained - self.predecessors = None; - } - - pub fn ensure_predecessors(&mut self, body: &Body<'_>) { - if self.predecessors.is_none() { - let mut result = IndexVec::from_elem(vec![], body.basic_blocks()); - for (bb, data) in body.basic_blocks().iter_enumerated() { - if let Some(ref term) = data.terminator { - for &tgt in term.successors() { - result[tgt].push(bb); - } - } - } - - self.predecessors = Some(result) - } - } - - /// This will recompute the predecessors cache if it is not available - fn predecessors(&mut self, body: &Body<'_>) -> &IndexVec<BasicBlock, Vec<BasicBlock>> { - self.ensure_predecessors(body); - self.predecessors.as_ref().unwrap() - } - - fn unwrap_predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] { - &self.predecessors.as_ref().unwrap()[bb] - } - - fn unwrap_predecessor_locations<'a>( - &'a self, - loc: Location, - body: &'a Body<'a>, - ) -> impl Iterator<Item = Location> + 'a { - let if_zero_locations = if loc.statement_index == 0 { - let predecessor_blocks = self.unwrap_predecessors_for(loc.block); - let num_predecessor_blocks = predecessor_blocks.len(); - Some( - (0..num_predecessor_blocks) - .map(move |i| predecessor_blocks[i]) - .map(move |bb| body.terminator_loc(bb)), - ) - } else { - None - }; - - let if_not_zero_locations = if loc.statement_index == 0 { - None - } else { - Some(Location { block: loc.block, statement_index: loc.statement_index - 1 }) - }; - - if_zero_locations.into_iter().flatten().chain(if_not_zero_locations) - } - - pub fn basic_blocks_mut<'a, 'tcx>( - &mut self, - body: &'a mut Body<'tcx>, - ) -> &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>> { - debug!("bbm: Clearing predecessors cache for body at: {:?}", body.span.data()); - self.invalidate_predecessors(); - &mut body.basic_blocks - } - - pub fn basic_blocks_and_local_decls_mut<'a, 'tcx>( - &mut self, - body: &'a mut Body<'tcx>, - ) -> (&'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &'a mut LocalDecls<'tcx>) { - debug!("bbaldm: Clearing predecessors cache for body at: {:?}", body.span.data()); - self.invalidate_predecessors(); - (&mut body.basic_blocks, &mut body.local_decls) - } -} - -#[derive(Clone, Debug, HashStable, RustcEncodable, RustcDecodable, TypeFoldable)] -pub struct BodyAndCache<'tcx> { - body: Body<'tcx>, - cache: Cache, -} - -impl BodyAndCache<'tcx> { - pub fn new(body: Body<'tcx>) -> Self { - Self { body, cache: Cache::new() } - } -} - -#[macro_export] -macro_rules! read_only { - ($body:expr) => {{ - $body.ensure_predecessors(); - $body.unwrap_read_only() - }}; -} - -impl BodyAndCache<'tcx> { - pub fn ensure_predecessors(&mut self) { - self.cache.ensure_predecessors(&self.body); - } - - pub fn predecessors(&mut self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> { - self.cache.predecessors(&self.body) - } - - pub fn unwrap_read_only(&self) -> ReadOnlyBodyAndCache<'_, 'tcx> { - ReadOnlyBodyAndCache::new(&self.body, &self.cache) - } - - pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> { - self.cache.basic_blocks_mut(&mut self.body) - } - - pub fn basic_blocks_and_local_decls_mut( - &mut self, - ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) { - self.cache.basic_blocks_and_local_decls_mut(&mut self.body) - } -} - -impl<'tcx> Index<BasicBlock> for BodyAndCache<'tcx> { - type Output = BasicBlockData<'tcx>; - - fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { - &self.body[index] - } -} - -impl<'tcx> IndexMut<BasicBlock> for BodyAndCache<'tcx> { - fn index_mut(&mut self, index: BasicBlock) -> &mut Self::Output { - &mut self.basic_blocks_mut()[index] - } -} - -impl<'tcx> Deref for BodyAndCache<'tcx> { - type Target = Body<'tcx>; - - fn deref(&self) -> &Self::Target { - &self.body - } -} - -impl<'tcx> DerefMut for BodyAndCache<'tcx> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.body - } -} - -#[derive(Copy, Clone, Debug)] -pub struct ReadOnlyBodyAndCache<'a, 'tcx> { - body: &'a Body<'tcx>, - cache: &'a Cache, -} - -impl ReadOnlyBodyAndCache<'a, 'tcx> { - fn new(body: &'a Body<'tcx>, cache: &'a Cache) -> Self { - assert!( - cache.predecessors.is_some(), - "Cannot construct ReadOnlyBodyAndCache without computed predecessors" - ); - Self { body, cache } - } - - pub fn predecessors(&self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> { - self.cache.predecessors.as_ref().unwrap() - } - - pub fn predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] { - self.cache.unwrap_predecessors_for(bb) - } - - pub fn predecessor_locations(&self, loc: Location) -> impl Iterator<Item = Location> + '_ { - self.cache.unwrap_predecessor_locations(loc, self.body) - } - - pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> { - &self.body.basic_blocks - } - - pub fn dominators(&self) -> Dominators<BasicBlock> { - dominators(self) - } -} - -impl graph::DirectedGraph for ReadOnlyBodyAndCache<'a, 'tcx> { - type Node = BasicBlock; -} - -impl graph::GraphPredecessors<'graph> for ReadOnlyBodyAndCache<'a, 'tcx> { - type Item = BasicBlock; - type Iter = IntoIter<BasicBlock>; -} - -impl graph::WithPredecessors for ReadOnlyBodyAndCache<'a, 'tcx> { - fn predecessors(&self, node: Self::Node) -> <Self as GraphPredecessors<'_>>::Iter { - self.cache.unwrap_predecessors_for(node).to_vec().into_iter() - } -} - -impl graph::WithNumNodes for ReadOnlyBodyAndCache<'a, 'tcx> { - fn num_nodes(&self) -> usize { - self.body.num_nodes() - } -} - -impl graph::WithStartNode for ReadOnlyBodyAndCache<'a, 'tcx> { - fn start_node(&self) -> Self::Node { - self.body.start_node() - } -} - -impl graph::WithSuccessors for ReadOnlyBodyAndCache<'a, 'tcx> { - fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter { - self.body.successors(node) - } -} - -impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for ReadOnlyBodyAndCache<'a, 'tcx> { - type Item = BasicBlock; - type Iter = iter::Cloned<Successors<'b>>; -} - -impl Deref for ReadOnlyBodyAndCache<'a, 'tcx> { - type Target = &'a Body<'tcx>; - - fn deref(&self) -> &Self::Target { - &self.body - } -} - -CloneTypeFoldableAndLiftImpls! { - Cache, -} diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs deleted file mode 100644 index 052603f6e5e..00000000000 --- a/src/librustc/mir/interpret/allocation.rs +++ /dev/null @@ -1,906 +0,0 @@ -//! The virtual memory representation of the MIR interpreter. - -use super::{ - read_target_uint, write_target_uint, AllocId, InterpResult, Pointer, Scalar, ScalarMaybeUndef, -}; - -use crate::ty::layout::{Align, Size}; - -use rustc_data_structures::sorted_map::SortedMap; -use rustc_target::abi::HasDataLayout; -use std::borrow::Cow; -use std::iter; -use std::ops::{Deref, DerefMut, Range}; -use syntax::ast::Mutability; - -// NOTE: When adding new fields, make sure to adjust the `Snapshot` impl in -// `src/librustc_mir/interpret/snapshot.rs`. -#[derive( - Clone, - Debug, - Eq, - PartialEq, - PartialOrd, - Ord, - Hash, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub struct Allocation<Tag = (), Extra = ()> { - /// The actual bytes of the allocation. - /// Note that the bytes of a pointer represent the offset of the pointer. - bytes: Vec<u8>, - /// Maps from byte addresses to extra data for each pointer. - /// Only the first byte of a pointer is inserted into the map; i.e., - /// every entry in this map applies to `pointer_size` consecutive bytes starting - /// at the given offset. - relocations: Relocations<Tag>, - /// Denotes which part of this allocation is initialized. - undef_mask: UndefMask, - /// The size of the allocation. Currently, must always equal `bytes.len()`. - pub size: Size, - /// The alignment of the allocation to detect unaligned reads. - pub align: Align, - /// `true` if the allocation is mutable. - /// Also used by codegen to determine if a static should be put into mutable memory, - /// which happens for `static mut` and `static` with interior mutability. - pub mutability: Mutability, - /// Extra state for the machine. - pub extra: Extra, -} - -pub trait AllocationExtra<Tag>: ::std::fmt::Debug + Clone { - // There is no constructor in here because the constructor's type depends - // on `MemoryKind`, and making things sufficiently generic leads to painful - // inference failure. - - /// Hook for performing extra checks on a memory read access. - /// - /// Takes read-only access to the allocation so we can keep all the memory read - /// operations take `&self`. Use a `RefCell` in `AllocExtra` if you - /// need to mutate. - #[inline(always)] - fn memory_read( - _alloc: &Allocation<Tag, Self>, - _ptr: Pointer<Tag>, - _size: Size, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Hook for performing extra checks on a memory write access. - #[inline(always)] - fn memory_written( - _alloc: &mut Allocation<Tag, Self>, - _ptr: Pointer<Tag>, - _size: Size, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Hook for performing extra checks on a memory deallocation. - /// `size` will be the size of the allocation. - #[inline(always)] - fn memory_deallocated( - _alloc: &mut Allocation<Tag, Self>, - _ptr: Pointer<Tag>, - _size: Size, - ) -> InterpResult<'tcx> { - Ok(()) - } -} - -// For `Tag = ()` and no extra state, we have a trivial implementation. -impl AllocationExtra<()> for () {} - -// The constructors are all without extra; the extra gets added by a machine hook later. -impl<Tag> Allocation<Tag> { - /// Creates a read-only allocation initialized by the given bytes - pub fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self { - let bytes = slice.into().into_owned(); - let size = Size::from_bytes(bytes.len() as u64); - Self { - bytes, - relocations: Relocations::new(), - undef_mask: UndefMask::new(size, true), - size, - align, - mutability: Mutability::Not, - extra: (), - } - } - - pub fn from_byte_aligned_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>) -> Self { - Allocation::from_bytes(slice, Align::from_bytes(1).unwrap()) - } - - pub fn undef(size: Size, align: Align) -> Self { - assert_eq!(size.bytes() as usize as u64, size.bytes()); - Allocation { - bytes: vec![0; size.bytes() as usize], - relocations: Relocations::new(), - undef_mask: UndefMask::new(size, false), - size, - align, - mutability: Mutability::Mut, - extra: (), - } - } -} - -impl Allocation<(), ()> { - /// Add Tag and Extra fields - pub fn with_tags_and_extra<T, E>( - self, - mut tagger: impl FnMut(AllocId) -> T, - extra: E, - ) -> Allocation<T, E> { - Allocation { - bytes: self.bytes, - size: self.size, - relocations: Relocations::from_presorted( - self.relocations - .iter() - // The allocations in the relocations (pointers stored *inside* this allocation) - // all get the base pointer tag. - .map(|&(offset, ((), alloc))| { - let tag = tagger(alloc); - (offset, (tag, alloc)) - }) - .collect(), - ), - undef_mask: self.undef_mask, - align: self.align, - mutability: self.mutability, - extra, - } - } -} - -/// Raw accessors. Provide access to otherwise private bytes. -impl<Tag, Extra> Allocation<Tag, Extra> { - pub fn len(&self) -> usize { - self.size.bytes() as usize - } - - /// Looks at a slice which may describe undefined bytes or describe a relocation. This differs - /// from `get_bytes_with_undef_and_ptr` in that it does no relocation checks (even on the - /// edges) at all. It further ignores `AllocationExtra` callbacks. - /// This must not be used for reads affecting the interpreter execution. - pub fn inspect_with_undef_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] { - &self.bytes[range] - } - - /// Returns the undef mask. - pub fn undef_mask(&self) -> &UndefMask { - &self.undef_mask - } - - /// Returns the relocation list. - pub fn relocations(&self) -> &Relocations<Tag> { - &self.relocations - } -} - -impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx Allocation {} - -/// Byte accessors. -impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { - /// Just a small local helper function to avoid a bit of code repetition. - /// Returns the range of this allocation that was meant. - #[inline] - fn check_bounds(&self, offset: Size, size: Size) -> Range<usize> { - let end = offset + size; // This does overflow checking. - assert_eq!( - end.bytes() as usize as u64, - end.bytes(), - "cannot handle this access on this host architecture" - ); - let end = end.bytes() as usize; - assert!( - end <= self.len(), - "Out-of-bounds access at offset {}, size {} in allocation of size {}", - offset.bytes(), - size.bytes(), - self.len() - ); - (offset.bytes() as usize)..end - } - - /// The last argument controls whether we error out when there are undefined - /// or pointer bytes. You should never call this, call `get_bytes` or - /// `get_bytes_with_undef_and_ptr` instead, - /// - /// This function also guarantees that the resulting pointer will remain stable - /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies - /// on that. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - fn get_bytes_internal( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - check_defined_and_ptr: bool, - ) -> InterpResult<'tcx, &[u8]> { - let range = self.check_bounds(ptr.offset, size); - - if check_defined_and_ptr { - self.check_defined(ptr, size)?; - self.check_relocations(cx, ptr, size)?; - } else { - // We still don't want relocations on the *edges*. - self.check_relocation_edges(cx, ptr, size)?; - } - - AllocationExtra::memory_read(self, ptr, size)?; - - Ok(&self.bytes[range]) - } - - /// Checks that these bytes are initialized and not pointer bytes, and then return them - /// as a slice. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods - /// on `InterpCx` instead. - #[inline] - pub fn get_bytes( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx, &[u8]> { - self.get_bytes_internal(cx, ptr, size, true) - } - - /// It is the caller's responsibility to handle undefined and pointer bytes. - /// However, this still checks that there are no relocations on the *edges*. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - #[inline] - pub fn get_bytes_with_undef_and_ptr( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx, &[u8]> { - self.get_bytes_internal(cx, ptr, size, false) - } - - /// Just calling this already marks everything as defined and removes relocations, - /// so be sure to actually put data there! - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods - /// on `InterpCx` instead. - pub fn get_bytes_mut( - &mut self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx, &mut [u8]> { - let range = self.check_bounds(ptr.offset, size); - - self.mark_definedness(ptr, size, true); - self.clear_relocations(cx, ptr, size)?; - - AllocationExtra::memory_written(self, ptr, size)?; - - Ok(&mut self.bytes[range]) - } -} - -/// Reading and writing. -impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { - /// Reads bytes until a `0` is encountered. Will error if the end of the allocation is reached - /// before a `0` is found. - /// - /// Most likely, you want to call `Memory::read_c_str` instead of this method. - pub fn read_c_str( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - ) -> InterpResult<'tcx, &[u8]> { - assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes()); - let offset = ptr.offset.bytes() as usize; - Ok(match self.bytes[offset..].iter().position(|&c| c == 0) { - Some(size) => { - let size_with_null = Size::from_bytes((size + 1) as u64); - // Go through `get_bytes` for checks and AllocationExtra hooks. - // We read the null, so we include it in the request, but we want it removed - // from the result, so we do subslicing. - &self.get_bytes(cx, ptr, size_with_null)?[..size] - } - // This includes the case where `offset` is out-of-bounds to begin with. - None => throw_unsup!(UnterminatedCString(ptr.erase_tag())), - }) - } - - /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a - /// relocation. If `allow_ptr_and_undef` is `false`, also enforces that the memory in the - /// given range contains neither relocations nor undef bytes. - pub fn check_bytes( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - allow_ptr_and_undef: bool, - ) -> InterpResult<'tcx> { - // Check bounds and relocations on the edges. - self.get_bytes_with_undef_and_ptr(cx, ptr, size)?; - // Check undef and ptr. - if !allow_ptr_and_undef { - self.check_defined(ptr, size)?; - self.check_relocations(cx, ptr, size)?; - } - Ok(()) - } - - /// Writes `src` to the memory starting at `ptr.offset`. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - /// Most likely, you want to call `Memory::write_bytes` instead of this method. - pub fn write_bytes( - &mut self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - src: impl IntoIterator<Item = u8>, - ) -> InterpResult<'tcx> { - let mut src = src.into_iter(); - let (lower, upper) = src.size_hint(); - let len = upper.expect("can only write bounded iterators"); - assert_eq!(lower, len, "can only write iterators with a precise length"); - let bytes = self.get_bytes_mut(cx, ptr, Size::from_bytes(len as u64))?; - // `zip` would stop when the first iterator ends; we want to definitely - // cover all of `bytes`. - for dest in bytes { - *dest = src.next().expect("iterator was shorter than it said it would be"); - } - src.next().expect_none("iterator was longer than it said it would be"); - Ok(()) - } - - /// Reads a *non-ZST* scalar. - /// - /// ZSTs can't be read for two reasons: - /// * byte-order cannot work with zero-element buffers; - /// * in order to obtain a `Pointer`, we need to check for ZSTness anyway due to integer - /// pointers being valid for ZSTs. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - /// Most likely, you want to call `InterpCx::read_scalar` instead of this method. - pub fn read_scalar( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx, ScalarMaybeUndef<Tag>> { - // `get_bytes_unchecked` tests relocation edges. - let bytes = self.get_bytes_with_undef_and_ptr(cx, ptr, size)?; - // Undef check happens *after* we established that the alignment is correct. - // We must not return `Ok()` for unaligned pointers! - if self.check_defined(ptr, size).is_err() { - // This inflates undefined bytes to the entire scalar, even if only a few - // bytes are undefined. - return Ok(ScalarMaybeUndef::Undef); - } - // Now we do the actual reading. - let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); - // See if we got a pointer. - if size != cx.data_layout().pointer_size { - // *Now*, we better make sure that the inside is free of relocations too. - self.check_relocations(cx, ptr, size)?; - } else { - match self.relocations.get(&ptr.offset) { - Some(&(tag, alloc_id)) => { - let ptr = Pointer::new_with_tag(alloc_id, Size::from_bytes(bits as u64), tag); - return Ok(ScalarMaybeUndef::Scalar(ptr.into())); - } - None => {} - } - } - // We don't. Just return the bits. - Ok(ScalarMaybeUndef::Scalar(Scalar::from_uint(bits, size))) - } - - /// Reads a pointer-sized scalar. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - /// Most likely, you want to call `InterpCx::read_scalar` instead of this method. - pub fn read_ptr_sized( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - ) -> InterpResult<'tcx, ScalarMaybeUndef<Tag>> { - self.read_scalar(cx, ptr, cx.data_layout().pointer_size) - } - - /// Writes a *non-ZST* scalar. - /// - /// ZSTs can't be read for two reasons: - /// * byte-order cannot work with zero-element buffers; - /// * in order to obtain a `Pointer`, we need to check for ZSTness anyway due to integer - /// pointers being valid for ZSTs. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - /// Most likely, you want to call `InterpCx::write_scalar` instead of this method. - pub fn write_scalar( - &mut self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - val: ScalarMaybeUndef<Tag>, - type_size: Size, - ) -> InterpResult<'tcx> { - let val = match val { - ScalarMaybeUndef::Scalar(scalar) => scalar, - ScalarMaybeUndef::Undef => { - self.mark_definedness(ptr, type_size, false); - return Ok(()); - } - }; - - let bytes = match val.to_bits_or_ptr(type_size, cx) { - Err(val) => val.offset.bytes() as u128, - Ok(data) => data, - }; - - let endian = cx.data_layout().endian; - let dst = self.get_bytes_mut(cx, ptr, type_size)?; - write_target_uint(endian, dst, bytes).unwrap(); - - // See if we have to also write a relocation. - match val { - Scalar::Ptr(val) => { - self.relocations.insert(ptr.offset, (val.tag, val.alloc_id)); - } - _ => {} - } - - Ok(()) - } - - /// Writes a pointer-sized scalar. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - /// Most likely, you want to call `InterpCx::write_scalar` instead of this method. - pub fn write_ptr_sized( - &mut self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - val: ScalarMaybeUndef<Tag>, - ) -> InterpResult<'tcx> { - let ptr_size = cx.data_layout().pointer_size; - self.write_scalar(cx, ptr.into(), val, ptr_size) - } -} - -/// Relocations. -impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> { - /// Returns all relocations overlapping with the given pointer-offset pair. - pub fn get_relocations( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> &[(Size, (Tag, AllocId))] { - // We have to go back `pointer_size - 1` bytes, as that one would still overlap with - // the beginning of this range. - let start = ptr.offset.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1); - let end = ptr.offset + size; // This does overflow checking. - self.relocations.range(Size::from_bytes(start)..end) - } - - /// Checks that there are no relocations overlapping with the given range. - #[inline(always)] - fn check_relocations( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx> { - if self.get_relocations(cx, ptr, size).is_empty() { - Ok(()) - } else { - throw_unsup!(ReadPointerAsBytes) - } - } - - /// Removes all relocations inside the given range. - /// If there are relocations overlapping with the edges, they - /// are removed as well *and* the bytes they cover are marked as - /// uninitialized. This is a somewhat odd "spooky action at a distance", - /// but it allows strictly more code to run than if we would just error - /// immediately in that case. - fn clear_relocations( - &mut self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx> { - // Find the start and end of the given range and its outermost relocations. - let (first, last) = { - // Find all relocations overlapping the given range. - let relocations = self.get_relocations(cx, ptr, size); - if relocations.is_empty() { - return Ok(()); - } - - ( - relocations.first().unwrap().0, - relocations.last().unwrap().0 + cx.data_layout().pointer_size, - ) - }; - let start = ptr.offset; - let end = start + size; - - // Mark parts of the outermost relocations as undefined if they partially fall outside the - // given range. - if first < start { - self.undef_mask.set_range(first, start, false); - } - if last > end { - self.undef_mask.set_range(end, last, false); - } - - // Forget all the relocations. - self.relocations.remove_range(first..last); - - Ok(()) - } - - /// Errors if there are relocations overlapping with the edges of the - /// given memory range. - #[inline] - fn check_relocation_edges( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx> { - self.check_relocations(cx, ptr, Size::ZERO)?; - self.check_relocations(cx, ptr.offset(size, cx)?, Size::ZERO)?; - Ok(()) - } -} - -/// Undefined bytes. -impl<'tcx, Tag, Extra> Allocation<Tag, Extra> { - /// Checks that a range of bytes is defined. If not, returns the `ReadUndefBytes` - /// error which will report the first byte which is undefined. - #[inline] - fn check_defined(&self, ptr: Pointer<Tag>, size: Size) -> InterpResult<'tcx> { - self.undef_mask - .is_range_defined(ptr.offset, ptr.offset + size) - .or_else(|idx| throw_unsup!(ReadUndefBytes(idx))) - } - - pub fn mark_definedness(&mut self, ptr: Pointer<Tag>, size: Size, new_state: bool) { - if size.bytes() == 0 { - return; - } - self.undef_mask.set_range(ptr.offset, ptr.offset + size, new_state); - } -} - -/// Run-length encoding of the undef mask. -/// Used to copy parts of a mask multiple times to another allocation. -pub struct AllocationDefinedness { - /// The definedness of the first range. - initial: bool, - /// The lengths of ranges that are run-length encoded. - /// The definedness of the ranges alternate starting with `initial`. - ranges: smallvec::SmallVec<[u64; 1]>, -} - -impl AllocationDefinedness { - pub fn all_bytes_undef(&self) -> bool { - // The `ranges` are run-length encoded and of alternating definedness. - // So if `ranges.len() > 1` then the second block is a range of defined. - !self.initial && self.ranges.len() == 1 - } -} - -/// Transferring the definedness mask to other allocations. -impl<Tag, Extra> Allocation<Tag, Extra> { - /// Creates a run-length encoding of the undef mask. - pub fn compress_undef_range(&self, src: Pointer<Tag>, size: Size) -> AllocationDefinedness { - // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`), - // a naive undef mask copying algorithm would repeatedly have to read the undef mask from - // the source and write it to the destination. Even if we optimized the memory accesses, - // we'd be doing all of this `repeat` times. - // Therefor we precompute a compressed version of the undef mask of the source value and - // then write it back `repeat` times without computing any more information from the source. - - // A precomputed cache for ranges of defined/undefined bits - // 0000010010001110 will become - // `[5, 1, 2, 1, 3, 3, 1]`, - // where each element toggles the state. - - let mut ranges = smallvec::SmallVec::<[u64; 1]>::new(); - let initial = self.undef_mask.get(src.offset); - let mut cur_len = 1; - let mut cur = initial; - - for i in 1..size.bytes() { - // FIXME: optimize to bitshift the current undef block's bits and read the top bit. - if self.undef_mask.get(src.offset + Size::from_bytes(i)) == cur { - cur_len += 1; - } else { - ranges.push(cur_len); - cur_len = 1; - cur = !cur; - } - } - - ranges.push(cur_len); - - AllocationDefinedness { ranges, initial } - } - - /// Applies multiple instances of the run-length encoding to the undef mask. - pub fn mark_compressed_undef_range( - &mut self, - defined: &AllocationDefinedness, - dest: Pointer<Tag>, - size: Size, - repeat: u64, - ) { - // An optimization where we can just overwrite an entire range of definedness bits if - // they are going to be uniformly `1` or `0`. - if defined.ranges.len() <= 1 { - self.undef_mask.set_range_inbounds( - dest.offset, - dest.offset + size * repeat, - defined.initial, - ); - return; - } - - for mut j in 0..repeat { - j *= size.bytes(); - j += dest.offset.bytes(); - let mut cur = defined.initial; - for range in &defined.ranges { - let old_j = j; - j += range; - self.undef_mask.set_range_inbounds( - Size::from_bytes(old_j), - Size::from_bytes(j), - cur, - ); - cur = !cur; - } - } - } -} - -/// Relocations. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct Relocations<Tag = (), Id = AllocId>(SortedMap<Size, (Tag, Id)>); - -impl<Tag, Id> Relocations<Tag, Id> { - pub fn new() -> Self { - Relocations(SortedMap::new()) - } - - // The caller must guarantee that the given relocations are already sorted - // by address and contain no duplicates. - pub fn from_presorted(r: Vec<(Size, (Tag, Id))>) -> Self { - Relocations(SortedMap::from_presorted_elements(r)) - } -} - -impl<Tag> Deref for Relocations<Tag> { - type Target = SortedMap<Size, (Tag, AllocId)>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl<Tag> DerefMut for Relocations<Tag> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -/// A partial, owned list of relocations to transfer into another allocation. -pub struct AllocationRelocations<Tag> { - relative_relocations: Vec<(Size, (Tag, AllocId))>, -} - -impl<Tag: Copy, Extra> Allocation<Tag, Extra> { - pub fn prepare_relocation_copy( - &self, - cx: &impl HasDataLayout, - src: Pointer<Tag>, - size: Size, - dest: Pointer<Tag>, - length: u64, - ) -> AllocationRelocations<Tag> { - let relocations = self.get_relocations(cx, src, size); - if relocations.is_empty() { - return AllocationRelocations { relative_relocations: Vec::new() }; - } - - let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize)); - - for i in 0..length { - new_relocations.extend(relocations.iter().map(|&(offset, reloc)| { - // compute offset for current repetition - let dest_offset = dest.offset + (i * size); - ( - // shift offsets from source allocation to destination allocation - offset + dest_offset - src.offset, - reloc, - ) - })); - } - - AllocationRelocations { relative_relocations: new_relocations } - } - - /// Applies a relocation copy. - /// The affected range, as defined in the parameters to `prepare_relocation_copy` is expected - /// to be clear of relocations. - pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations<Tag>) { - self.relocations.insert_presorted(relocations.relative_relocations); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Undefined byte tracking -//////////////////////////////////////////////////////////////////////////////// - -type Block = u64; - -/// A bitmask where each bit refers to the byte with the same index. If the bit is `true`, the byte -/// is defined. If it is `false` the byte is undefined. -#[derive( - Clone, - Debug, - Eq, - PartialEq, - PartialOrd, - Ord, - Hash, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub struct UndefMask { - blocks: Vec<Block>, - len: Size, -} - -impl UndefMask { - pub const BLOCK_SIZE: u64 = 64; - - pub fn new(size: Size, state: bool) -> Self { - let mut m = UndefMask { blocks: vec![], len: Size::ZERO }; - m.grow(size, state); - m - } - - /// Checks whether the range `start..end` (end-exclusive) is entirely defined. - /// - /// Returns `Ok(())` if it's defined. Otherwise returns the index of the byte - /// at which the first undefined access begins. - #[inline] - pub fn is_range_defined(&self, start: Size, end: Size) -> Result<(), Size> { - if end > self.len { - return Err(self.len); - } - - // FIXME(oli-obk): optimize this for allocations larger than a block. - let idx = (start.bytes()..end.bytes()).map(|i| Size::from_bytes(i)).find(|&i| !self.get(i)); - - match idx { - Some(idx) => Err(idx), - None => Ok(()), - } - } - - pub fn set_range(&mut self, start: Size, end: Size, new_state: bool) { - let len = self.len; - if end > len { - self.grow(end - len, new_state); - } - self.set_range_inbounds(start, end, new_state); - } - - pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) { - let (blocka, bita) = bit_index(start); - let (blockb, bitb) = bit_index(end); - if blocka == blockb { - // First set all bits except the first `bita`, - // then unset the last `64 - bitb` bits. - let range = if bitb == 0 { - u64::max_value() << bita - } else { - (u64::max_value() << bita) & (u64::max_value() >> (64 - bitb)) - }; - if new_state { - self.blocks[blocka] |= range; - } else { - self.blocks[blocka] &= !range; - } - return; - } - // across block boundaries - if new_state { - // Set `bita..64` to `1`. - self.blocks[blocka] |= u64::max_value() << bita; - // Set `0..bitb` to `1`. - if bitb != 0 { - self.blocks[blockb] |= u64::max_value() >> (64 - bitb); - } - // Fill in all the other blocks (much faster than one bit at a time). - for block in (blocka + 1)..blockb { - self.blocks[block] = u64::max_value(); - } - } else { - // Set `bita..64` to `0`. - self.blocks[blocka] &= !(u64::max_value() << bita); - // Set `0..bitb` to `0`. - if bitb != 0 { - self.blocks[blockb] &= !(u64::max_value() >> (64 - bitb)); - } - // Fill in all the other blocks (much faster than one bit at a time). - for block in (blocka + 1)..blockb { - self.blocks[block] = 0; - } - } - } - - #[inline] - pub fn get(&self, i: Size) -> bool { - let (block, bit) = bit_index(i); - (self.blocks[block] & (1 << bit)) != 0 - } - - #[inline] - pub fn set(&mut self, i: Size, new_state: bool) { - let (block, bit) = bit_index(i); - self.set_bit(block, bit, new_state); - } - - #[inline] - fn set_bit(&mut self, block: usize, bit: usize, new_state: bool) { - if new_state { - self.blocks[block] |= 1 << bit; - } else { - self.blocks[block] &= !(1 << bit); - } - } - - pub fn grow(&mut self, amount: Size, new_state: bool) { - if amount.bytes() == 0 { - return; - } - let unused_trailing_bits = self.blocks.len() as u64 * Self::BLOCK_SIZE - self.len.bytes(); - if amount.bytes() > unused_trailing_bits { - let additional_blocks = amount.bytes() / Self::BLOCK_SIZE + 1; - assert_eq!(additional_blocks as usize as u64, additional_blocks); - self.blocks.extend( - // FIXME(oli-obk): optimize this by repeating `new_state as Block`. - iter::repeat(0).take(additional_blocks as usize), - ); - } - let start = self.len; - self.len += amount; - self.set_range_inbounds(start, start + amount, new_state); - } -} - -#[inline] -fn bit_index(bits: Size) -> (usize, usize) { - let bits = bits.bytes(); - let a = bits / UndefMask::BLOCK_SIZE; - let b = bits % UndefMask::BLOCK_SIZE; - assert_eq!(a as usize as u64, a); - assert_eq!(b as usize as u64, b); - (a as usize, b as usize) -} diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs deleted file mode 100644 index a23ff6bd66d..00000000000 --- a/src/librustc/mir/interpret/error.rs +++ /dev/null @@ -1,614 +0,0 @@ -use super::{CheckInAllocMsg, Pointer, RawConst, ScalarMaybeUndef}; - -use crate::hir::map::definitions::DefPathData; -use crate::mir; -use crate::mir::interpret::ConstValue; -use crate::ty::layout::{Align, LayoutError, Size}; -use crate::ty::query::TyCtxtAt; -use crate::ty::{self, layout, Ty}; - -use backtrace::Backtrace; -use rustc_errors::{struct_span_err, DiagnosticBuilder}; -use rustc_hir as hir; -use rustc_macros::HashStable; -use rustc_span::{Pos, Span}; -use rustc_target::spec::abi::Abi; -use std::{any::Any, env, fmt}; - -#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)] -pub enum ErrorHandled { - /// Already reported a lint or an error for this evaluation. - Reported, - /// Don't emit an error, the evaluation failed because the MIR was generic - /// and the substs didn't fully monomorphize it. - TooGeneric, -} - -impl ErrorHandled { - pub fn assert_reported(self) { - match self { - ErrorHandled::Reported => {} - ErrorHandled::TooGeneric => bug!( - "MIR interpretation failed without reporting an error \ - even though it was fully monomorphized" - ), - } - } -} - -CloneTypeFoldableImpls! { - ErrorHandled, -} - -pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>; -pub type ConstEvalResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>; - -#[derive(Debug)] -pub struct ConstEvalErr<'tcx> { - pub span: Span, - pub error: crate::mir::interpret::InterpError<'tcx>, - pub stacktrace: Vec<FrameInfo<'tcx>>, -} - -#[derive(Debug)] -pub struct FrameInfo<'tcx> { - /// This span is in the caller. - pub call_site: Span, - pub instance: ty::Instance<'tcx>, - pub lint_root: Option<hir::HirId>, -} - -impl<'tcx> fmt::Display for FrameInfo<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ty::tls::with(|tcx| { - if tcx.def_key(self.instance.def_id()).disambiguated_data.data - == DefPathData::ClosureExpr - { - write!(f, "inside call to closure")?; - } else { - write!(f, "inside call to `{}`", self.instance)?; - } - if !self.call_site.is_dummy() { - let lo = tcx.sess.source_map().lookup_char_pos(self.call_site.lo()); - write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?; - } - Ok(()) - }) - } -} - -impl<'tcx> ConstEvalErr<'tcx> { - pub fn struct_error( - &self, - tcx: TyCtxtAt<'tcx>, - message: &str, - emit: impl FnOnce(DiagnosticBuilder<'_>), - ) -> Result<(), ErrorHandled> { - self.struct_generic(tcx, message, emit, None) - } - - pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled { - match self.struct_error(tcx, message, |mut e| e.emit()) { - Ok(_) => ErrorHandled::Reported, - Err(x) => x, - } - } - - pub fn report_as_lint( - &self, - tcx: TyCtxtAt<'tcx>, - message: &str, - lint_root: hir::HirId, - span: Option<Span>, - ) -> ErrorHandled { - match self.struct_generic( - tcx, - message, - |mut lint: DiagnosticBuilder<'_>| { - // Apply the span. - if let Some(span) = span { - let primary_spans = lint.span.primary_spans().to_vec(); - // point at the actual error as the primary span - lint.replace_span_with(span); - // point to the `const` statement as a secondary span - // they don't have any label - for sp in primary_spans { - if sp != span { - lint.span_label(sp, ""); - } - } - } - lint.emit(); - }, - Some(lint_root), - ) { - Ok(_) => ErrorHandled::Reported, - Err(err) => err, - } - } - - /// Create a diagnostic for this const eval error. - /// - /// Sets the message passed in via `message` and adds span labels with detailed error - /// information before handing control back to `emit` to do any final processing. - /// It's the caller's responsibility to call emit(), stash(), etc. within the `emit` - /// function to dispose of the diagnostic properly. - /// - /// If `lint_root.is_some()` report it as a lint, else report it as a hard error. - /// (Except that for some errors, we ignore all that -- see `must_error` below.) - fn struct_generic( - &self, - tcx: TyCtxtAt<'tcx>, - message: &str, - emit: impl FnOnce(DiagnosticBuilder<'_>), - lint_root: Option<hir::HirId>, - ) -> Result<(), ErrorHandled> { - let must_error = match self.error { - err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { - return Err(ErrorHandled::TooGeneric); - } - err_inval!(TypeckError) => return Err(ErrorHandled::Reported), - // We must *always* hard error on these, even if the caller wants just a lint. - err_inval!(Layout(LayoutError::SizeOverflow(_))) => true, - _ => false, - }; - trace!("reporting const eval failure at {:?}", self.span); - - let err_msg = match &self.error { - InterpError::MachineStop(msg) => { - // A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`). - // Should be turned into a string by now. - msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone() - } - err => err.to_string(), - }; - - let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| { - if let Some(span_msg) = span_msg { - err.span_label(self.span, span_msg); - } - // Add spans for the stacktrace. - // Skip the last, which is just the environment of the constant. The stacktrace - // is sometimes empty because we create "fake" eval contexts in CTFE to do work - // on constant values. - if self.stacktrace.len() > 0 { - for frame_info in &self.stacktrace[..self.stacktrace.len() - 1] { - err.span_label(frame_info.call_site, frame_info.to_string()); - } - } - // Let the caller finish the job. - emit(err) - }; - - if must_error { - // The `message` makes little sense here, this is a more serious error than the - // caller thinks anyway. - // See <https://github.com/rust-lang/rust/pull/63152>. - finish(struct_error(tcx, &err_msg), None); - } else { - // Regular case. - if let Some(lint_root) = lint_root { - // Report as lint. - let hir_id = self - .stacktrace - .iter() - .rev() - .filter_map(|frame| frame.lint_root) - .next() - .unwrap_or(lint_root); - tcx.struct_span_lint_hir( - rustc_session::lint::builtin::CONST_ERR, - hir_id, - tcx.span, - |lint| finish(lint.build(message), Some(err_msg)), - ); - } else { - // Report as hard error. - finish(struct_error(tcx, message), Some(err_msg)); - } - } - Ok(()) - } -} - -pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> { - struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg) -} - -/// Packages the kind of error we got from the const code interpreter -/// up with a Rust-level backtrace of where the error occurred. -/// Thsese should always be constructed by calling `.into()` on -/// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*` -/// macros for this. -#[derive(Debug)] -pub struct InterpErrorInfo<'tcx> { - pub kind: InterpError<'tcx>, - backtrace: Option<Box<Backtrace>>, -} - -impl fmt::Display for InterpErrorInfo<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.kind) - } -} - -impl InterpErrorInfo<'_> { - pub fn print_backtrace(&mut self) { - if let Some(ref mut backtrace) = self.backtrace { - print_backtrace(&mut *backtrace); - } - } -} - -fn print_backtrace(backtrace: &mut Backtrace) { - backtrace.resolve(); - eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace); -} - -impl From<ErrorHandled> for InterpErrorInfo<'tcx> { - fn from(err: ErrorHandled) -> Self { - match err { - ErrorHandled::Reported => err_inval!(ReferencedConstant), - ErrorHandled::TooGeneric => err_inval!(TooGeneric), - } - .into() - } -} - -impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> { - fn from(kind: InterpError<'tcx>) -> Self { - let backtrace = match env::var("RUSTC_CTFE_BACKTRACE") { - // Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present". - Ok(ref val) if val != "0" => { - let mut backtrace = Backtrace::new_unresolved(); - - if val == "immediate" { - // Print it now. - print_backtrace(&mut backtrace); - None - } else { - Some(Box::new(backtrace)) - } - } - _ => None, - }; - InterpErrorInfo { kind, backtrace } - } -} - -/// Error information for when the program we executed turned out not to actually be a valid -/// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp -/// where we work on generic code or execution does not have all information available. -pub enum InvalidProgramInfo<'tcx> { - /// Resolution can fail if we are in a too generic context. - TooGeneric, - /// Cannot compute this constant because it depends on another one - /// which already produced an error. - ReferencedConstant, - /// Abort in case type errors are reached. - TypeckError, - /// An error occurred during layout computation. - Layout(layout::LayoutError<'tcx>), -} - -impl fmt::Debug for InvalidProgramInfo<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use InvalidProgramInfo::*; - match self { - TooGeneric => write!(f, "encountered overly generic constant"), - ReferencedConstant => write!(f, "referenced constant has errors"), - TypeckError => write!(f, "encountered constants with type errors, stopping evaluation"), - Layout(ref err) => write!(f, "{}", err), - } - } -} - -/// Error information for when the program caused Undefined Behavior. -pub enum UndefinedBehaviorInfo { - /// Free-form case. Only for errors that are never caught! - Ub(String), - /// Free-form case for experimental UB. Only for errors that are never caught! - UbExperimental(String), - /// Unreachable code was executed. - Unreachable, - /// An enum discriminant was set to a value which was outside the range of valid values. - InvalidDiscriminant(ScalarMaybeUndef), - /// A slice/array index projection went out-of-bounds. - BoundsCheckFailed { len: u64, index: u64 }, - /// Something was divided by 0 (x / 0). - DivisionByZero, - /// Something was "remainded" by 0 (x % 0). - RemainderByZero, - /// Overflowing inbounds pointer arithmetic. - PointerArithOverflow, -} - -impl fmt::Debug for UndefinedBehaviorInfo { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use UndefinedBehaviorInfo::*; - match self { - Ub(msg) | UbExperimental(msg) => write!(f, "{}", msg), - Unreachable => write!(f, "entering unreachable code"), - InvalidDiscriminant(val) => write!(f, "encountering invalid enum discriminant {}", val), - BoundsCheckFailed { ref len, ref index } => write!( - f, - "indexing out of bounds: the len is {:?} but the index is {:?}", - len, index - ), - DivisionByZero => write!(f, "dividing by zero"), - RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"), - PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), - } - } -} - -/// Error information for when the program did something that might (or might not) be correct -/// to do according to the Rust spec, but due to limitations in the interpreter, the -/// operation could not be carried out. These limitations can differ between CTFE and the -/// Miri engine, e.g., CTFE does not support casting pointers to "real" integers. -/// -/// Currently, we also use this as fall-back error kind for errors that have not been -/// categorized yet. -pub enum UnsupportedOpInfo<'tcx> { - /// Free-form case. Only for errors that are never caught! - Unsupported(String), - - /// When const-prop encounters a situation it does not support, it raises this error. - /// This must not allocate for performance reasons. - ConstPropUnsupported(&'tcx str), - - // -- Everything below is not categorized yet -- - FunctionAbiMismatch(Abi, Abi), - FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>), - FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>), - FunctionArgCountMismatch, - UnterminatedCString(Pointer), - DanglingPointerDeref, - DoubleFree, - InvalidMemoryAccess, - InvalidFunctionPointer, - InvalidBool, - PointerOutOfBounds { - ptr: Pointer, - msg: CheckInAllocMsg, - allocation_size: Size, - }, - InvalidNullPointerUsage, - ReadPointerAsBytes, - ReadBytesAsPointer, - ReadForeignStatic, - InvalidPointerMath, - ReadUndefBytes(Size), - DeadLocal, - InvalidBoolOp(mir::BinOp), - UnimplementedTraitSelection, - CalledClosureAsFunction, - NoMirFor(String), - DerefFunctionPointer, - ExecuteMemory, - InvalidChar(u128), - OutOfTls, - TlsOutOfBounds, - AlignmentCheckFailed { - required: Align, - has: Align, - }, - ValidationFailure(String), - VtableForArgumentlessMethod, - ModifiedConstantMemory, - ModifiedStatic, - TypeNotPrimitive(Ty<'tcx>), - ReallocatedWrongMemoryKind(String, String), - DeallocatedWrongMemoryKind(String, String), - ReallocateNonBasePtr, - DeallocateNonBasePtr, - IncorrectAllocationInformation(Size, Size, Align, Align), - HeapAllocZeroBytes, - HeapAllocNonPowerOfTwoAlignment(u64), - ReadFromReturnPointer, - PathNotFound(Vec<String>), - TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>), -} - -impl fmt::Debug for UnsupportedOpInfo<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use UnsupportedOpInfo::*; - match self { - PointerOutOfBounds { ptr, msg, allocation_size } => write!( - f, - "{} failed: pointer must be in-bounds at offset {}, \ - but is outside bounds of allocation {} which has size {}", - msg, - ptr.offset.bytes(), - ptr.alloc_id, - allocation_size.bytes() - ), - ValidationFailure(ref err) => write!(f, "type validation failed: {}", err), - NoMirFor(ref func) => write!(f, "no MIR for `{}`", func), - FunctionAbiMismatch(caller_abi, callee_abi) => write!( - f, - "tried to call a function with ABI {:?} using caller ABI {:?}", - callee_abi, caller_abi - ), - FunctionArgMismatch(caller_ty, callee_ty) => write!( - f, - "tried to call a function with argument of type {:?} \ - passing data of type {:?}", - callee_ty, caller_ty - ), - TransmuteSizeDiff(from_ty, to_ty) => write!( - f, - "tried to transmute from {:?} to {:?}, but their sizes differed", - from_ty, to_ty - ), - FunctionRetMismatch(caller_ty, callee_ty) => write!( - f, - "tried to call a function with return type {:?} \ - passing return place of type {:?}", - callee_ty, caller_ty - ), - FunctionArgCountMismatch => { - write!(f, "tried to call a function with incorrect number of arguments") - } - ReallocatedWrongMemoryKind(ref old, ref new) => { - write!(f, "tried to reallocate memory from `{}` to `{}`", old, new) - } - DeallocatedWrongMemoryKind(ref old, ref new) => { - write!(f, "tried to deallocate `{}` memory but gave `{}` as the kind", old, new) - } - InvalidChar(c) => { - write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c) - } - AlignmentCheckFailed { required, has } => write!( - f, - "tried to access memory with alignment {}, but alignment {} is required", - has.bytes(), - required.bytes() - ), - TypeNotPrimitive(ty) => write!(f, "expected primitive type, got {}", ty), - PathNotFound(ref path) => write!(f, "cannot find path {:?}", path), - IncorrectAllocationInformation(size, size2, align, align2) => write!( - f, - "incorrect alloc info: expected size {} and align {}, \ - got size {} and align {}", - size.bytes(), - align.bytes(), - size2.bytes(), - align2.bytes() - ), - InvalidMemoryAccess => write!(f, "tried to access memory through an invalid pointer"), - DanglingPointerDeref => write!(f, "dangling pointer was dereferenced"), - DoubleFree => write!(f, "tried to deallocate dangling pointer"), - InvalidFunctionPointer => { - write!(f, "tried to use a function pointer after offsetting it") - } - InvalidBool => write!(f, "invalid boolean value read"), - InvalidNullPointerUsage => write!(f, "invalid use of NULL pointer"), - ReadPointerAsBytes => write!( - f, - "a raw memory access tried to access part of a pointer value as raw \ - bytes" - ), - ReadBytesAsPointer => { - write!(f, "a memory access tried to interpret some bytes as a pointer") - } - ReadForeignStatic => write!(f, "tried to read from foreign (extern) static"), - InvalidPointerMath => write!( - f, - "attempted to do invalid arithmetic on pointers that would leak base \ - addresses, e.g., comparing pointers into different allocations" - ), - DeadLocal => write!(f, "tried to access a dead local variable"), - DerefFunctionPointer => write!(f, "tried to dereference a function pointer"), - ExecuteMemory => write!(f, "tried to treat a memory pointer as a function pointer"), - OutOfTls => write!(f, "reached the maximum number of representable TLS keys"), - TlsOutOfBounds => write!(f, "accessed an invalid (unallocated) TLS key"), - CalledClosureAsFunction => { - write!(f, "tried to call a closure through a function pointer") - } - VtableForArgumentlessMethod => { - write!(f, "tried to call a vtable function without arguments") - } - ModifiedConstantMemory => write!(f, "tried to modify constant memory"), - ModifiedStatic => write!( - f, - "tried to modify a static's initial value from another static's \ - initializer" - ), - ReallocateNonBasePtr => write!( - f, - "tried to reallocate with a pointer not to the beginning of an \ - existing object" - ), - DeallocateNonBasePtr => write!( - f, - "tried to deallocate with a pointer not to the beginning of an \ - existing object" - ), - HeapAllocZeroBytes => write!(f, "tried to re-, de- or allocate zero bytes on the heap"), - ReadFromReturnPointer => write!(f, "tried to read from the return pointer"), - UnimplementedTraitSelection => { - write!(f, "there were unresolved type arguments during trait selection") - } - InvalidBoolOp(_) => write!(f, "invalid boolean operation"), - UnterminatedCString(_) => write!( - f, - "attempted to get length of a null-terminated string, but no null \ - found before end of allocation" - ), - ReadUndefBytes(_) => write!(f, "attempted to read undefined bytes"), - HeapAllocNonPowerOfTwoAlignment(_) => write!( - f, - "tried to re-, de-, or allocate heap memory with alignment that is \ - not a power of two" - ), - Unsupported(ref msg) => write!(f, "{}", msg), - ConstPropUnsupported(ref msg) => { - write!(f, "Constant propagation encountered an unsupported situation: {}", msg) - } - } - } -} - -/// Error information for when the program exhausted the resources granted to it -/// by the interpreter. -pub enum ResourceExhaustionInfo { - /// The stack grew too big. - StackFrameLimitReached, - /// The program ran into an infinite loop. - InfiniteLoop, -} - -impl fmt::Debug for ResourceExhaustionInfo { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use ResourceExhaustionInfo::*; - match self { - StackFrameLimitReached => { - write!(f, "reached the configured maximum number of stack frames") - } - InfiniteLoop => write!( - f, - "duplicate interpreter state observed here, const evaluation will never \ - terminate" - ), - } - } -} - -pub enum InterpError<'tcx> { - /// The program caused undefined behavior. - UndefinedBehavior(UndefinedBehaviorInfo), - /// The program did something the interpreter does not support (some of these *might* be UB - /// but the interpreter is not sure). - Unsupported(UnsupportedOpInfo<'tcx>), - /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...). - InvalidProgram(InvalidProgramInfo<'tcx>), - /// The program exhausted the interpreter's resources (stack/heap too big, - /// execution takes too long, ...). - ResourceExhaustion(ResourceExhaustionInfo), - /// Stop execution for a machine-controlled reason. This is never raised by - /// the core engine itself. - MachineStop(Box<dyn Any + Send>), -} - -pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>; - -impl fmt::Display for InterpError<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Forward `Display` to `Debug`. - write!(f, "{:?}", self) - } -} - -impl fmt::Debug for InterpError<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use InterpError::*; - match *self { - Unsupported(ref msg) => write!(f, "{:?}", msg), - InvalidProgram(ref msg) => write!(f, "{:?}", msg), - UndefinedBehavior(ref msg) => write!(f, "{:?}", msg), - ResourceExhaustion(ref msg) => write!(f, "{:?}", msg), - MachineStop(_) => bug!("unhandled MachineStop"), - } - } -} diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs deleted file mode 100644 index c62f9a049a0..00000000000 --- a/src/librustc/mir/interpret/mod.rs +++ /dev/null @@ -1,565 +0,0 @@ -//! An interpreter for MIR used in CTFE and by miri. - -#[macro_export] -macro_rules! err_unsup { - ($($tt:tt)*) => { - $crate::mir::interpret::InterpError::Unsupported( - $crate::mir::interpret::UnsupportedOpInfo::$($tt)* - ) - }; -} - -#[macro_export] -macro_rules! err_unsup_format { - ($($tt:tt)*) => { err_unsup!(Unsupported(format!($($tt)*))) }; -} - -#[macro_export] -macro_rules! err_inval { - ($($tt:tt)*) => { - $crate::mir::interpret::InterpError::InvalidProgram( - $crate::mir::interpret::InvalidProgramInfo::$($tt)* - ) - }; -} - -#[macro_export] -macro_rules! err_ub { - ($($tt:tt)*) => { - $crate::mir::interpret::InterpError::UndefinedBehavior( - $crate::mir::interpret::UndefinedBehaviorInfo::$($tt)* - ) - }; -} - -#[macro_export] -macro_rules! err_ub_format { - ($($tt:tt)*) => { err_ub!(Ub(format!($($tt)*))) }; -} - -#[macro_export] -macro_rules! err_exhaust { - ($($tt:tt)*) => { - $crate::mir::interpret::InterpError::ResourceExhaustion( - $crate::mir::interpret::ResourceExhaustionInfo::$($tt)* - ) - }; -} - -#[macro_export] -macro_rules! throw_unsup { - ($($tt:tt)*) => { return Err(err_unsup!($($tt)*).into()) }; -} - -#[macro_export] -macro_rules! throw_unsup_format { - ($($tt:tt)*) => { throw_unsup!(Unsupported(format!($($tt)*))) }; -} - -#[macro_export] -macro_rules! throw_inval { - ($($tt:tt)*) => { return Err(err_inval!($($tt)*).into()) }; -} - -#[macro_export] -macro_rules! throw_ub { - ($($tt:tt)*) => { return Err(err_ub!($($tt)*).into()) }; -} - -#[macro_export] -macro_rules! throw_ub_format { - ($($tt:tt)*) => { throw_ub!(Ub(format!($($tt)*))) }; -} - -#[macro_export] -macro_rules! throw_exhaust { - ($($tt:tt)*) => { return Err(err_exhaust!($($tt)*).into()) }; -} - -#[macro_export] -macro_rules! throw_machine_stop { - ($($tt:tt)*) => { - return Err($crate::mir::interpret::InterpError::MachineStop(Box::new($($tt)*)).into()) - }; -} - -mod allocation; -mod error; -mod pointer; -mod queries; -mod value; - -pub use self::error::{ - struct_error, ConstEvalErr, ConstEvalRawResult, ConstEvalResult, ErrorHandled, FrameInfo, - InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, ResourceExhaustionInfo, - UndefinedBehaviorInfo, UnsupportedOpInfo, -}; - -pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUndef}; - -pub use self::allocation::{Allocation, AllocationExtra, Relocations, UndefMask}; - -pub use self::pointer::{CheckInAllocMsg, Pointer, PointerArithmetic}; - -use crate::mir; -use crate::ty::codec::TyDecoder; -use crate::ty::layout::{self, Size}; -use crate::ty::subst::GenericArgKind; -use crate::ty::{self, Instance, Ty, TyCtxt}; -use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::{HashMapExt, Lock}; -use rustc_data_structures::tiny_list::TinyList; -use rustc_hir::def_id::DefId; -use rustc_macros::HashStable; -use rustc_serialize::{Decodable, Encodable, Encoder}; -use std::fmt; -use std::io; -use std::num::NonZeroU32; -use std::sync::atomic::{AtomicU32, Ordering}; -use syntax::ast::LitKind; - -/// Uniquely identifies one of the following: -/// - A constant -/// - A static -/// - A const fn where all arguments (if any) are zero-sized types -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] -#[derive(HashStable, Lift)] -pub struct GlobalId<'tcx> { - /// For a constant or static, the `Instance` of the item itself. - /// For a promoted global, the `Instance` of the function they belong to. - pub instance: ty::Instance<'tcx>, - - /// The index for promoted globals within their function's `mir::Body`. - pub promoted: Option<mir::Promoted>, -} - -/// Input argument for `tcx.lit_to_const`. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable)] -pub struct LitToConstInput<'tcx> { - /// The absolute value of the resultant constant. - pub lit: &'tcx LitKind, - /// The type of the constant. - pub ty: Ty<'tcx>, - /// If the constant is negative. - pub neg: bool, -} - -/// Error type for `tcx.lit_to_const`. -#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable)] -pub enum LitToConstError { - /// The literal's inferred type did not match the expected `ty` in the input. - /// This is used for graceful error handling (`delay_span_bug`) in - /// type checking (`AstConv::ast_const_to_const`). - TypeError, - UnparseableFloat, - Reported, -} - -#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct AllocId(pub u64); - -impl fmt::Debug for AllocId { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "alloc{}", self.0) - } -} - -impl rustc_serialize::UseSpecializedEncodable for AllocId {} -impl rustc_serialize::UseSpecializedDecodable for AllocId {} - -#[derive(RustcDecodable, RustcEncodable)] -enum AllocDiscriminant { - Alloc, - Fn, - Static, -} - -pub fn specialized_encode_alloc_id<'tcx, E: Encoder>( - encoder: &mut E, - tcx: TyCtxt<'tcx>, - alloc_id: AllocId, -) -> Result<(), E::Error> { - let alloc: GlobalAlloc<'tcx> = - tcx.alloc_map.lock().get(alloc_id).expect("no value for given alloc ID"); - match alloc { - GlobalAlloc::Memory(alloc) => { - trace!("encoding {:?} with {:#?}", alloc_id, alloc); - AllocDiscriminant::Alloc.encode(encoder)?; - alloc.encode(encoder)?; - } - GlobalAlloc::Function(fn_instance) => { - trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); - AllocDiscriminant::Fn.encode(encoder)?; - fn_instance.encode(encoder)?; - } - GlobalAlloc::Static(did) => { - // References to statics doesn't need to know about their allocations, - // just about its `DefId`. - AllocDiscriminant::Static.encode(encoder)?; - did.encode(encoder)?; - } - } - Ok(()) -} - -// Used to avoid infinite recursion when decoding cyclic allocations. -type DecodingSessionId = NonZeroU32; - -#[derive(Clone)] -enum State { - Empty, - InProgressNonAlloc(TinyList<DecodingSessionId>), - InProgress(TinyList<DecodingSessionId>, AllocId), - Done(AllocId), -} - -pub struct AllocDecodingState { - // For each `AllocId`, we keep track of which decoding state it's currently in. - decoding_state: Vec<Lock<State>>, - // The offsets of each allocation in the data stream. - data_offsets: Vec<u32>, -} - -impl AllocDecodingState { - pub fn new_decoding_session(&self) -> AllocDecodingSession<'_> { - static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0); - let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst); - - // Make sure this is never zero. - let session_id = DecodingSessionId::new((counter & 0x7FFFFFFF) + 1).unwrap(); - - AllocDecodingSession { state: self, session_id } - } - - pub fn new(data_offsets: Vec<u32>) -> Self { - let decoding_state = vec![Lock::new(State::Empty); data_offsets.len()]; - - Self { decoding_state, data_offsets } - } -} - -#[derive(Copy, Clone)] -pub struct AllocDecodingSession<'s> { - state: &'s AllocDecodingState, - session_id: DecodingSessionId, -} - -impl<'s> AllocDecodingSession<'s> { - /// Decodes an `AllocId` in a thread-safe way. - pub fn decode_alloc_id<D>(&self, decoder: &mut D) -> Result<AllocId, D::Error> - where - D: TyDecoder<'tcx>, - { - // Read the index of the allocation. - let idx = decoder.read_u32()? as usize; - let pos = self.state.data_offsets[idx] as usize; - - // Decode the `AllocDiscriminant` now so that we know if we have to reserve an - // `AllocId`. - let (alloc_kind, pos) = decoder.with_position(pos, |decoder| { - let alloc_kind = AllocDiscriminant::decode(decoder)?; - Ok((alloc_kind, decoder.position())) - })?; - - // Check the decoding state to see if it's already decoded or if we should - // decode it here. - let alloc_id = { - let mut entry = self.state.decoding_state[idx].lock(); - - match *entry { - State::Done(alloc_id) => { - return Ok(alloc_id); - } - ref mut entry @ State::Empty => { - // We are allowed to decode. - match alloc_kind { - AllocDiscriminant::Alloc => { - // If this is an allocation, we need to reserve an - // `AllocId` so we can decode cyclic graphs. - let alloc_id = decoder.tcx().alloc_map.lock().reserve(); - *entry = - State::InProgress(TinyList::new_single(self.session_id), alloc_id); - Some(alloc_id) - } - AllocDiscriminant::Fn | AllocDiscriminant::Static => { - // Fns and statics cannot be cyclic, and their `AllocId` - // is determined later by interning. - *entry = - State::InProgressNonAlloc(TinyList::new_single(self.session_id)); - None - } - } - } - State::InProgressNonAlloc(ref mut sessions) => { - if sessions.contains(&self.session_id) { - bug!("this should be unreachable"); - } else { - // Start decoding concurrently. - sessions.insert(self.session_id); - None - } - } - State::InProgress(ref mut sessions, alloc_id) => { - if sessions.contains(&self.session_id) { - // Don't recurse. - return Ok(alloc_id); - } else { - // Start decoding concurrently. - sessions.insert(self.session_id); - Some(alloc_id) - } - } - } - }; - - // Now decode the actual data. - let alloc_id = decoder.with_position(pos, |decoder| { - match alloc_kind { - AllocDiscriminant::Alloc => { - let alloc = <&'tcx Allocation as Decodable>::decode(decoder)?; - // We already have a reserved `AllocId`. - let alloc_id = alloc_id.unwrap(); - trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc); - decoder.tcx().alloc_map.lock().set_alloc_id_same_memory(alloc_id, alloc); - Ok(alloc_id) - } - AllocDiscriminant::Fn => { - assert!(alloc_id.is_none()); - trace!("creating fn alloc ID"); - let instance = ty::Instance::decode(decoder)?; - trace!("decoded fn alloc instance: {:?}", instance); - let alloc_id = decoder.tcx().alloc_map.lock().create_fn_alloc(instance); - Ok(alloc_id) - } - AllocDiscriminant::Static => { - assert!(alloc_id.is_none()); - trace!("creating extern static alloc ID"); - let did = DefId::decode(decoder)?; - trace!("decoded static def-ID: {:?}", did); - let alloc_id = decoder.tcx().alloc_map.lock().create_static_alloc(did); - Ok(alloc_id) - } - } - })?; - - self.state.decoding_state[idx].with_lock(|entry| { - *entry = State::Done(alloc_id); - }); - - Ok(alloc_id) - } -} - -impl fmt::Display for AllocId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -/// An allocation in the global (tcx-managed) memory can be either a function pointer, -/// a static, or a "real" allocation with some data in it. -#[derive(Debug, Clone, Eq, PartialEq, Hash, RustcDecodable, RustcEncodable, HashStable)] -pub enum GlobalAlloc<'tcx> { - /// The alloc ID is used as a function pointer. - Function(Instance<'tcx>), - /// The alloc ID points to a "lazy" static variable that did not get computed (yet). - /// This is also used to break the cycle in recursive statics. - Static(DefId), - /// The alloc ID points to memory. - Memory(&'tcx Allocation), -} - -pub struct AllocMap<'tcx> { - /// Maps `AllocId`s to their corresponding allocations. - alloc_map: FxHashMap<AllocId, GlobalAlloc<'tcx>>, - - /// Used to ensure that statics and functions only get one associated `AllocId`. - /// Should never contain a `GlobalAlloc::Memory`! - // - // FIXME: Should we just have two separate dedup maps for statics and functions each? - dedup: FxHashMap<GlobalAlloc<'tcx>, AllocId>, - - /// The `AllocId` to assign to the next requested ID. - /// Always incremented; never gets smaller. - next_id: AllocId, -} - -impl<'tcx> AllocMap<'tcx> { - pub fn new() -> Self { - AllocMap { alloc_map: Default::default(), dedup: Default::default(), next_id: AllocId(0) } - } - - /// Obtains a new allocation ID that can be referenced but does not - /// yet have an allocation backing it. - /// - /// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such - /// an `AllocId` from a query. - pub fn reserve(&mut self) -> AllocId { - let next = self.next_id; - self.next_id.0 = self.next_id.0.checked_add(1).expect( - "You overflowed a u64 by incrementing by 1... \ - You've just earned yourself a free drink if we ever meet. \ - Seriously, how did you do that?!", - ); - next - } - - /// Reserves a new ID *if* this allocation has not been dedup-reserved before. - /// Should only be used for function pointers and statics, we don't want - /// to dedup IDs for "real" memory! - fn reserve_and_set_dedup(&mut self, alloc: GlobalAlloc<'tcx>) -> AllocId { - match alloc { - GlobalAlloc::Function(..) | GlobalAlloc::Static(..) => {} - GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"), - } - if let Some(&alloc_id) = self.dedup.get(&alloc) { - return alloc_id; - } - let id = self.reserve(); - debug!("creating alloc {:?} with id {}", alloc, id); - self.alloc_map.insert(id, alloc.clone()); - self.dedup.insert(alloc, id); - id - } - - /// Generates an `AllocId` for a static or return a cached one in case this function has been - /// called on the same static before. - pub fn create_static_alloc(&mut self, static_id: DefId) -> AllocId { - self.reserve_and_set_dedup(GlobalAlloc::Static(static_id)) - } - - /// Generates an `AllocId` for a function. Depending on the function type, - /// this might get deduplicated or assigned a new ID each time. - pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> AllocId { - // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated - // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be - // duplicated across crates. - // We thus generate a new `AllocId` for every mention of a function. This means that - // `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true. - // However, formatting code relies on function identity (see #58320), so we only do - // this for generic functions. Lifetime parameters are ignored. - let is_generic = instance.substs.into_iter().any(|kind| match kind.unpack() { - GenericArgKind::Lifetime(_) => false, - _ => true, - }); - if is_generic { - // Get a fresh ID. - let id = self.reserve(); - self.alloc_map.insert(id, GlobalAlloc::Function(instance)); - id - } else { - // Deduplicate. - self.reserve_and_set_dedup(GlobalAlloc::Function(instance)) - } - } - - /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical - /// `Allocation` with a different `AllocId`. - /// Statics with identical content will still point to the same `Allocation`, i.e., - /// their data will be deduplicated through `Allocation` interning -- but they - /// are different places in memory and as such need different IDs. - pub fn create_memory_alloc(&mut self, mem: &'tcx Allocation) -> AllocId { - let id = self.reserve(); - self.set_alloc_id_memory(id, mem); - id - } - - /// Returns `None` in case the `AllocId` is dangling. An `InterpretCx` can still have a - /// local `Allocation` for that `AllocId`, but having such an `AllocId` in a constant is - /// illegal and will likely ICE. - /// This function exists to allow const eval to detect the difference between evaluation- - /// local dangling pointers and allocations in constants/statics. - #[inline] - pub fn get(&self, id: AllocId) -> Option<GlobalAlloc<'tcx>> { - self.alloc_map.get(&id).cloned() - } - - /// Panics if the `AllocId` does not refer to an `Allocation` - pub fn unwrap_memory(&self, id: AllocId) -> &'tcx Allocation { - match self.get(id) { - Some(GlobalAlloc::Memory(mem)) => mem, - _ => bug!("expected allocation ID {} to point to memory", id), - } - } - - /// Panics if the `AllocId` does not refer to a function - pub fn unwrap_fn(&self, id: AllocId) -> Instance<'tcx> { - match self.get(id) { - Some(GlobalAlloc::Function(instance)) => instance, - _ => bug!("expected allocation ID {} to point to a function", id), - } - } - - /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to - /// call this function twice, even with the same `Allocation` will ICE the compiler. - pub fn set_alloc_id_memory(&mut self, id: AllocId, mem: &'tcx Allocation) { - if let Some(old) = self.alloc_map.insert(id, GlobalAlloc::Memory(mem)) { - bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old); - } - } - - /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called - /// twice for the same `(AllocId, Allocation)` pair. - fn set_alloc_id_same_memory(&mut self, id: AllocId, mem: &'tcx Allocation) { - self.alloc_map.insert_same(id, GlobalAlloc::Memory(mem)); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Methods to access integers in the target endianness -//////////////////////////////////////////////////////////////////////////////// - -#[inline] -pub fn write_target_uint( - endianness: layout::Endian, - mut target: &mut [u8], - data: u128, -) -> Result<(), io::Error> { - let len = target.len(); - match endianness { - layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len), - layout::Endian::Big => target.write_uint128::<BigEndian>(data, len), - } -} - -#[inline] -pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> { - match endianness { - layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()), - layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()), - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Methods to facilitate working with signed integers stored in a u128 -//////////////////////////////////////////////////////////////////////////////// - -/// Truncates `value` to `size` bits and then sign-extend it to 128 bits -/// (i.e., if it is negative, fill with 1's on the left). -#[inline] -pub fn sign_extend(value: u128, size: Size) -> u128 { - let size = size.bits(); - if size == 0 { - // Truncated until nothing is left. - return 0; - } - // Sign-extend it. - let shift = 128 - size; - // Shift the unsigned value to the left, then shift back to the right as signed - // (essentially fills with FF on the left). - (((value << shift) as i128) >> shift) as u128 -} - -/// Truncates `value` to `size` bits. -#[inline] -pub fn truncate(value: u128, size: Size) -> u128 { - let size = size.bits(); - if size == 0 { - // Truncated until nothing is left. - return 0; - } - let shift = 128 - size; - // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). - (value << shift) >> shift -} diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs deleted file mode 100644 index a4974fb541b..00000000000 --- a/src/librustc/mir/interpret/pointer.rs +++ /dev/null @@ -1,232 +0,0 @@ -use super::{AllocId, InterpResult}; - -use crate::ty::layout::{self, HasDataLayout, Size}; - -use rustc_macros::HashStable; - -use std::convert::TryFrom; -use std::fmt::{self, Display}; - -/// Used by `check_in_alloc` to indicate context of check -#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)] -pub enum CheckInAllocMsg { - MemoryAccessTest, - NullPointerTest, - PointerArithmeticTest, - InboundsTest, -} - -impl Display for CheckInAllocMsg { - /// When this is printed as an error the context looks like this - /// "{test name} failed: pointer must be in-bounds at offset..." - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - CheckInAllocMsg::MemoryAccessTest => "Memory access", - CheckInAllocMsg::NullPointerTest => "Null pointer test", - CheckInAllocMsg::PointerArithmeticTest => "Pointer arithmetic", - CheckInAllocMsg::InboundsTest => "Inbounds test", - } - ) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Pointer arithmetic -//////////////////////////////////////////////////////////////////////////////// - -pub trait PointerArithmetic: layout::HasDataLayout { - // These are not supposed to be overridden. - - #[inline(always)] - fn pointer_size(&self) -> Size { - self.data_layout().pointer_size - } - - #[inline] - fn usize_max(&self) -> u64 { - let max_usize_plus_1 = 1u128 << self.pointer_size().bits(); - u64::try_from(max_usize_plus_1 - 1).unwrap() - } - - #[inline] - fn isize_max(&self) -> i64 { - let max_isize_plus_1 = 1u128 << (self.pointer_size().bits() - 1); - i64::try_from(max_isize_plus_1 - 1).unwrap() - } - - /// Helper function: truncate given value-"overflowed flag" pair to pointer size and - /// update "overflowed flag" if there was an overflow. - /// This should be called by all the other methods before returning! - #[inline] - fn truncate_to_ptr(&self, (val, over): (u64, bool)) -> (u64, bool) { - let val = val as u128; - let max_ptr_plus_1 = 1u128 << self.pointer_size().bits(); - ((val % max_ptr_plus_1) as u64, over || val >= max_ptr_plus_1) - } - - #[inline] - fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) { - let res = val.overflowing_add(i); - self.truncate_to_ptr(res) - } - - // Overflow checking only works properly on the range from -u64 to +u64. - #[inline] - fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) { - // FIXME: is it possible to over/underflow here? - if i < 0 { - // Trickery to ensure that `i64::min_value()` works fine: compute `n = -i`. - // This formula only works for true negative values; it overflows for zero! - let n = u64::max_value() - (i as u64) + 1; - let res = val.overflowing_sub(n); - self.truncate_to_ptr(res) - } else { - self.overflowing_offset(val, i as u64) - } - } - - #[inline] - fn offset<'tcx>(&self, val: u64, i: u64) -> InterpResult<'tcx, u64> { - let (res, over) = self.overflowing_offset(val, i); - if over { throw_ub!(PointerArithOverflow) } else { Ok(res) } - } - - #[inline] - fn signed_offset<'tcx>(&self, val: u64, i: i64) -> InterpResult<'tcx, u64> { - let (res, over) = self.overflowing_signed_offset(val, i128::from(i)); - if over { throw_ub!(PointerArithOverflow) } else { Ok(res) } - } -} - -impl<T: layout::HasDataLayout> PointerArithmetic for T {} - -/// `Pointer` is generic over the type that represents a reference to `Allocation`s, -/// thus making it possible for the most convenient representation to be used in -/// each context. -/// -/// Defaults to the index based and loosely coupled `AllocId`. -/// -/// `Pointer` is also generic over the `Tag` associated with each pointer, -/// which is used to do provenance tracking during execution. -#[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - RustcEncodable, - RustcDecodable, - Hash, - HashStable -)] -pub struct Pointer<Tag = (), Id = AllocId> { - pub alloc_id: Id, - pub offset: Size, - pub tag: Tag, -} - -static_assert_size!(Pointer, 16); - -impl<Tag: fmt::Debug, Id: fmt::Debug> fmt::Debug for Pointer<Tag, Id> { - default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}+{:x}[{:?}]", self.alloc_id, self.offset.bytes(), self.tag) - } -} -// Specialization for no tag -impl<Id: fmt::Debug> fmt::Debug for Pointer<(), Id> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}+{:x}", self.alloc_id, self.offset.bytes()) - } -} - -/// Produces a `Pointer` that points to the beginning of the `Allocation`. -impl From<AllocId> for Pointer { - #[inline(always)] - fn from(alloc_id: AllocId) -> Self { - Pointer::new(alloc_id, Size::ZERO) - } -} - -impl Pointer<()> { - #[inline(always)] - pub fn new(alloc_id: AllocId, offset: Size) -> Self { - Pointer { alloc_id, offset, tag: () } - } - - #[inline(always)] - pub fn with_tag<Tag>(self, tag: Tag) -> Pointer<Tag> { - Pointer::new_with_tag(self.alloc_id, self.offset, tag) - } -} - -impl<'tcx, Tag> Pointer<Tag> { - #[inline(always)] - pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self { - Pointer { alloc_id, offset, tag } - } - - #[inline] - pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> { - Ok(Pointer::new_with_tag( - self.alloc_id, - Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?), - self.tag, - )) - } - - #[inline] - pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) { - let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes()); - (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over) - } - - #[inline(always)] - pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self { - self.overflowing_offset(i, cx).0 - } - - #[inline] - pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> { - Ok(Pointer::new_with_tag( - self.alloc_id, - Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?), - self.tag, - )) - } - - #[inline] - pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) { - let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i); - (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over) - } - - #[inline(always)] - pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self { - self.overflowing_signed_offset(i128::from(i), cx).0 - } - - #[inline(always)] - pub fn erase_tag(self) -> Pointer { - Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () } - } - - /// Test if the pointer is "inbounds" of an allocation of the given size. - /// A pointer is "inbounds" even if its offset is equal to the size; this is - /// a "one-past-the-end" pointer. - #[inline(always)] - pub fn check_inbounds_alloc( - self, - allocation_size: Size, - msg: CheckInAllocMsg, - ) -> InterpResult<'tcx, ()> { - if self.offset > allocation_size { - throw_unsup!(PointerOutOfBounds { ptr: self.erase_tag(), msg, allocation_size }) - } else { - Ok(()) - } - } -} diff --git a/src/librustc/mir/interpret/queries.rs b/src/librustc/mir/interpret/queries.rs deleted file mode 100644 index ed57f81e782..00000000000 --- a/src/librustc/mir/interpret/queries.rs +++ /dev/null @@ -1,78 +0,0 @@ -use super::{ConstEvalResult, ErrorHandled, GlobalId}; - -use crate::mir; -use crate::ty::subst::{InternalSubsts, SubstsRef}; -use crate::ty::{self, TyCtxt}; -use rustc_hir::def_id::DefId; -use rustc_span::Span; - -impl<'tcx> TyCtxt<'tcx> { - /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts - /// that can't take any generic arguments like statics, const items or enum discriminants. If a - /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. - pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> { - // In some situations def_id will have substitutions within scope, but they aren't allowed - // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions - // into `const_eval` which will return `ErrorHandled::ToGeneric` if any og them are - // encountered. - let substs = InternalSubsts::identity_for_item(self, def_id); - let instance = ty::Instance::new(def_id, substs); - let cid = GlobalId { instance, promoted: None }; - let param_env = self.param_env(def_id).with_reveal_all(); - self.const_eval_validated(param_env.and(cid)) - } - - /// Resolves and evaluates a constant. - /// - /// The constant can be located on a trait like `<A as B>::C`, in which case the given - /// substitutions and environment are used to resolve the constant. Alternatively if the - /// constant has generic parameters in scope the substitutions are used to evaluate the value of - /// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count - /// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still - /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is - /// returned. - pub fn const_eval_resolve( - self, - param_env: ty::ParamEnv<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, - promoted: Option<mir::Promoted>, - span: Option<Span>, - ) -> ConstEvalResult<'tcx> { - let instance = ty::Instance::resolve(self, param_env, def_id, substs); - if let Some(instance) = instance { - if let Some(promoted) = promoted { - self.const_eval_promoted(param_env, instance, promoted) - } else { - self.const_eval_instance(param_env, instance, span) - } - } else { - Err(ErrorHandled::TooGeneric) - } - } - - pub fn const_eval_instance( - self, - param_env: ty::ParamEnv<'tcx>, - instance: ty::Instance<'tcx>, - span: Option<Span>, - ) -> ConstEvalResult<'tcx> { - let cid = GlobalId { instance, promoted: None }; - if let Some(span) = span { - self.at(span).const_eval_validated(param_env.and(cid)) - } else { - self.const_eval_validated(param_env.and(cid)) - } - } - - /// Evaluate a promoted constant. - pub fn const_eval_promoted( - self, - param_env: ty::ParamEnv<'tcx>, - instance: ty::Instance<'tcx>, - promoted: mir::Promoted, - ) -> ConstEvalResult<'tcx> { - let cid = GlobalId { instance, promoted: Some(promoted) }; - self.const_eval_validated(param_env.and(cid)) - } -} diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs deleted file mode 100644 index 2c146b5d7b4..00000000000 --- a/src/librustc/mir/interpret/value.rs +++ /dev/null @@ -1,679 +0,0 @@ -use rustc_apfloat::{ - ieee::{Double, Single}, - Float, -}; -use rustc_macros::HashStable; -use std::fmt; - -use crate::ty::{ - layout::{HasDataLayout, Size}, - ParamEnv, Ty, TyCtxt, -}; - -use super::{sign_extend, truncate, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; - -/// Represents the result of a raw const operation, pre-validation. -#[derive(Clone, HashStable)] -pub struct RawConst<'tcx> { - // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory` - // (so you can use `AllocMap::unwrap_memory`). - pub alloc_id: AllocId, - pub ty: Ty<'tcx>, -} - -/// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for -/// array length computations, enum discriminants and the pattern matching logic. -#[derive( - Copy, - Clone, - Debug, - Eq, - PartialEq, - PartialOrd, - Ord, - RustcEncodable, - RustcDecodable, - Hash, - HashStable -)] -pub enum ConstValue<'tcx> { - /// Used only for types with `layout::abi::Scalar` ABI and ZSTs. - /// - /// Not using the enum `Value` to encode that this must not be `Undef`. - Scalar(Scalar), - - /// Used only for `&[u8]` and `&str` - Slice { data: &'tcx Allocation, start: usize, end: usize }, - - /// A value not represented/representable by `Scalar` or `Slice` - ByRef { - /// The backing memory of the value, may contain more memory than needed for just the value - /// in order to share `Allocation`s between values - alloc: &'tcx Allocation, - /// Offset into `alloc` - offset: Size, - }, -} - -#[cfg(target_arch = "x86_64")] -static_assert_size!(ConstValue<'_>, 32); - -impl<'tcx> ConstValue<'tcx> { - #[inline] - pub fn try_to_scalar(&self) -> Option<Scalar> { - match *self { - ConstValue::ByRef { .. } | ConstValue::Slice { .. } => None, - ConstValue::Scalar(val) => Some(val), - } - } - - pub fn try_to_bits(&self, size: Size) -> Option<u128> { - self.try_to_scalar()?.to_bits(size).ok() - } - - pub fn try_to_bits_for_ty( - &self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ty: Ty<'tcx>, - ) -> Option<u128> { - let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size; - self.try_to_bits(size) - } - - pub fn from_bool(b: bool) -> Self { - ConstValue::Scalar(Scalar::from_bool(b)) - } - - pub fn from_u64(i: u64) -> Self { - ConstValue::Scalar(Scalar::from_u64(i)) - } - - pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self { - ConstValue::Scalar(Scalar::from_machine_usize(i, cx)) - } -} - -/// A `Scalar` represents an immediate, primitive value existing outside of a -/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in -/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes -/// of a simple value or a pointer into another `Allocation` -#[derive( - Clone, - Copy, - Eq, - PartialEq, - Ord, - PartialOrd, - RustcEncodable, - RustcDecodable, - Hash, - HashStable -)] -pub enum Scalar<Tag = (), Id = AllocId> { - /// The raw bytes of a simple value. - Raw { - /// The first `size` bytes of `data` are the value. - /// Do not try to read less or more bytes than that. The remaining bytes must be 0. - data: u128, - size: u8, - }, - - /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of - /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the - /// relocation and its associated offset together as a `Pointer` here. - Ptr(Pointer<Tag, Id>), -} - -#[cfg(target_arch = "x86_64")] -static_assert_size!(Scalar, 24); - -impl<Tag: fmt::Debug, Id: fmt::Debug> fmt::Debug for Scalar<Tag, Id> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Scalar::Ptr(ptr) => write!(f, "{:?}", ptr), - &Scalar::Raw { data, size } => { - Scalar::check_data(data, size); - if size == 0 { - write!(f, "<ZST>") - } else { - // Format as hex number wide enough to fit any value of the given `size`. - // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014". - write!(f, "0x{:>0width$x}", data, width = (size * 2) as usize) - } - } - } - } -} - -impl<Tag> fmt::Display for Scalar<Tag> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Scalar::Ptr(_) => write!(f, "a pointer"), - Scalar::Raw { data, .. } => write!(f, "{}", data), - } - } -} - -impl<Tag> From<Single> for Scalar<Tag> { - #[inline(always)] - fn from(f: Single) -> Self { - Scalar::from_f32(f) - } -} - -impl<Tag> From<Double> for Scalar<Tag> { - #[inline(always)] - fn from(f: Double) -> Self { - Scalar::from_f64(f) - } -} - -impl Scalar<()> { - #[inline(always)] - fn check_data(data: u128, size: u8) { - debug_assert_eq!( - truncate(data, Size::from_bytes(size as u64)), - data, - "Scalar value {:#x} exceeds size of {} bytes", - data, - size - ); - } - - /// Tag this scalar with `new_tag` if it is a pointer, leave it unchanged otherwise. - /// - /// Used by `MemPlace::replace_tag`. - #[inline] - pub fn with_tag<Tag>(self, new_tag: Tag) -> Scalar<Tag> { - match self { - Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_tag(new_tag)), - Scalar::Raw { data, size } => Scalar::Raw { data, size }, - } - } -} - -impl<'tcx, Tag> Scalar<Tag> { - /// Erase the tag from the scalar, if any. - /// - /// Used by error reporting code to avoid having the error type depend on `Tag`. - #[inline] - pub fn erase_tag(self) -> Scalar { - match self { - Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()), - Scalar::Raw { data, size } => Scalar::Raw { data, size }, - } - } - - #[inline] - pub fn ptr_null(cx: &impl HasDataLayout) -> Self { - Scalar::Raw { data: 0, size: cx.data_layout().pointer_size.bytes() as u8 } - } - - #[inline] - pub fn zst() -> Self { - Scalar::Raw { data: 0, size: 0 } - } - - #[inline] - pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> { - let dl = cx.data_layout(); - match self { - Scalar::Raw { data, size } => { - assert_eq!(size as u64, dl.pointer_size.bytes()); - Ok(Scalar::Raw { data: dl.offset(data as u64, i.bytes())? as u128, size }) - } - Scalar::Ptr(ptr) => ptr.offset(i, dl).map(Scalar::Ptr), - } - } - - #[inline] - pub fn ptr_wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self { - let dl = cx.data_layout(); - match self { - Scalar::Raw { data, size } => { - assert_eq!(size as u64, dl.pointer_size.bytes()); - Scalar::Raw { data: dl.overflowing_offset(data as u64, i.bytes()).0 as u128, size } - } - Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_offset(i, dl)), - } - } - - #[inline] - pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> { - let dl = cx.data_layout(); - match self { - Scalar::Raw { data, size } => { - assert_eq!(size as u64, dl.pointer_size().bytes()); - Ok(Scalar::Raw { data: dl.signed_offset(data as u64, i)? as u128, size }) - } - Scalar::Ptr(ptr) => ptr.signed_offset(i, dl).map(Scalar::Ptr), - } - } - - #[inline] - pub fn ptr_wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self { - let dl = cx.data_layout(); - match self { - Scalar::Raw { data, size } => { - assert_eq!(size as u64, dl.pointer_size.bytes()); - Scalar::Raw { - data: dl.overflowing_signed_offset(data as u64, i128::from(i)).0 as u128, - size, - } - } - Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_signed_offset(i, dl)), - } - } - - #[inline] - pub fn from_bool(b: bool) -> Self { - Scalar::Raw { data: b as u128, size: 1 } - } - - #[inline] - pub fn from_char(c: char) -> Self { - Scalar::Raw { data: c as u128, size: 4 } - } - - #[inline] - pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> { - let i = i.into(); - if truncate(i, size) == i { - Some(Scalar::Raw { data: i, size: size.bytes() as u8 }) - } else { - None - } - } - - #[inline] - pub fn from_uint(i: impl Into<u128>, size: Size) -> Self { - let i = i.into(); - Self::try_from_uint(i, size) - .unwrap_or_else(|| bug!("Unsigned value {:#x} does not fit in {} bits", i, size.bits())) - } - - #[inline] - pub fn from_u8(i: u8) -> Self { - Scalar::Raw { data: i as u128, size: 1 } - } - - #[inline] - pub fn from_u16(i: u16) -> Self { - Scalar::Raw { data: i as u128, size: 2 } - } - - #[inline] - pub fn from_u32(i: u32) -> Self { - Scalar::Raw { data: i as u128, size: 4 } - } - - #[inline] - pub fn from_u64(i: u64) -> Self { - Scalar::Raw { data: i as u128, size: 8 } - } - - #[inline] - pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self { - Self::from_uint(i, cx.data_layout().pointer_size) - } - - #[inline] - pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> { - let i = i.into(); - // `into` performed sign extension, we have to truncate - let truncated = truncate(i as u128, size); - if sign_extend(truncated, size) as i128 == i { - Some(Scalar::Raw { data: truncated, size: size.bytes() as u8 }) - } else { - None - } - } - - #[inline] - pub fn from_int(i: impl Into<i128>, size: Size) -> Self { - let i = i.into(); - Self::try_from_int(i, size) - .unwrap_or_else(|| bug!("Signed value {:#x} does not fit in {} bits", i, size.bits())) - } - - #[inline] - pub fn from_machine_isize(i: i64, cx: &impl HasDataLayout) -> Self { - Self::from_int(i, cx.data_layout().pointer_size) - } - - #[inline] - pub fn from_f32(f: Single) -> Self { - // We trust apfloat to give us properly truncated data. - Scalar::Raw { data: f.to_bits(), size: 4 } - } - - #[inline] - pub fn from_f64(f: Double) -> Self { - // We trust apfloat to give us properly truncated data. - Scalar::Raw { data: f.to_bits(), size: 8 } - } - - /// This is very rarely the method you want! You should dispatch on the type - /// and use `force_bits`/`assert_bits`/`force_ptr`/`assert_ptr`. - /// This method only exists for the benefit of low-level memory operations - /// as well as the implementation of the `force_*` methods. - #[inline] - pub fn to_bits_or_ptr( - self, - target_size: Size, - cx: &impl HasDataLayout, - ) -> Result<u128, Pointer<Tag>> { - match self { - Scalar::Raw { data, size } => { - assert_eq!(target_size.bytes(), size as u64); - assert_ne!(size, 0, "you should never look at the bits of a ZST"); - Scalar::check_data(data, size); - Ok(data) - } - Scalar::Ptr(ptr) => { - assert_eq!(target_size, cx.data_layout().pointer_size); - Err(ptr) - } - } - } - - #[inline(always)] - pub fn check_raw(data: u128, size: u8, target_size: Size) { - assert_eq!(target_size.bytes(), size as u64); - assert_ne!(size, 0, "you should never look at the bits of a ZST"); - Scalar::check_data(data, size); - } - - /// Do not call this method! Use either `assert_bits` or `force_bits`. - #[inline] - pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> { - match self { - Scalar::Raw { data, size } => { - Self::check_raw(data, size, target_size); - Ok(data) - } - Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes), - } - } - - #[inline(always)] - pub fn assert_bits(self, target_size: Size) -> u128 { - self.to_bits(target_size).expect("expected Raw bits but got a Pointer") - } - - /// Do not call this method! Use either `assert_ptr` or `force_ptr`. - /// This method is intentionally private, do not make it public. - #[inline] - fn to_ptr(self) -> InterpResult<'tcx, Pointer<Tag>> { - match self { - Scalar::Raw { data: 0, .. } => throw_unsup!(InvalidNullPointerUsage), - Scalar::Raw { .. } => throw_unsup!(ReadBytesAsPointer), - Scalar::Ptr(p) => Ok(p), - } - } - - #[inline(always)] - pub fn assert_ptr(self) -> Pointer<Tag> { - self.to_ptr().expect("expected a Pointer but got Raw bits") - } - - /// Do not call this method! Dispatch based on the type instead. - #[inline] - pub fn is_bits(self) -> bool { - match self { - Scalar::Raw { .. } => true, - _ => false, - } - } - - /// Do not call this method! Dispatch based on the type instead. - #[inline] - pub fn is_ptr(self) -> bool { - match self { - Scalar::Ptr(_) => true, - _ => false, - } - } - - pub fn to_bool(self) -> InterpResult<'tcx, bool> { - match self { - Scalar::Raw { data: 0, size: 1 } => Ok(false), - Scalar::Raw { data: 1, size: 1 } => Ok(true), - _ => throw_unsup!(InvalidBool), - } - } - - pub fn to_char(self) -> InterpResult<'tcx, char> { - let val = self.to_u32()?; - match ::std::char::from_u32(val) { - Some(c) => Ok(c), - None => throw_unsup!(InvalidChar(val as u128)), - } - } - - #[inline] - fn to_unsigned_with_bit_width(self, bits: u64) -> InterpResult<'static, u128> { - let sz = Size::from_bits(bits); - self.to_bits(sz) - } - - /// Converts the scalar to produce an `u8`. Fails if the scalar is a pointer. - pub fn to_u8(self) -> InterpResult<'static, u8> { - self.to_unsigned_with_bit_width(8).map(|v| v as u8) - } - - /// Converts the scalar to produce an `u16`. Fails if the scalar is a pointer. - pub fn to_u16(self) -> InterpResult<'static, u16> { - self.to_unsigned_with_bit_width(16).map(|v| v as u16) - } - - /// Converts the scalar to produce an `u32`. Fails if the scalar is a pointer. - pub fn to_u32(self) -> InterpResult<'static, u32> { - self.to_unsigned_with_bit_width(32).map(|v| v as u32) - } - - /// Converts the scalar to produce an `u64`. Fails if the scalar is a pointer. - pub fn to_u64(self) -> InterpResult<'static, u64> { - self.to_unsigned_with_bit_width(64).map(|v| v as u64) - } - - pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'static, u64> { - let b = self.to_bits(cx.data_layout().pointer_size)?; - Ok(b as u64) - } - - #[inline] - fn to_signed_with_bit_width(self, bits: u64) -> InterpResult<'static, i128> { - let sz = Size::from_bits(bits); - let b = self.to_bits(sz)?; - Ok(sign_extend(b, sz) as i128) - } - - /// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer. - pub fn to_i8(self) -> InterpResult<'static, i8> { - self.to_signed_with_bit_width(8).map(|v| v as i8) - } - - /// Converts the scalar to produce an `i16`. Fails if the scalar is a pointer. - pub fn to_i16(self) -> InterpResult<'static, i16> { - self.to_signed_with_bit_width(16).map(|v| v as i16) - } - - /// Converts the scalar to produce an `i32`. Fails if the scalar is a pointer. - pub fn to_i32(self) -> InterpResult<'static, i32> { - self.to_signed_with_bit_width(32).map(|v| v as i32) - } - - /// Converts the scalar to produce an `i64`. Fails if the scalar is a pointer. - pub fn to_i64(self) -> InterpResult<'static, i64> { - self.to_signed_with_bit_width(64).map(|v| v as i64) - } - - pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'static, i64> { - let sz = cx.data_layout().pointer_size; - let b = self.to_bits(sz)?; - let b = sign_extend(b, sz) as i128; - Ok(b as i64) - } - - #[inline] - pub fn to_f32(self) -> InterpResult<'static, Single> { - // Going through `u32` to check size and truncation. - Ok(Single::from_bits(self.to_u32()? as u128)) - } - - #[inline] - pub fn to_f64(self) -> InterpResult<'static, Double> { - // Going through `u64` to check size and truncation. - Ok(Double::from_bits(self.to_u64()? as u128)) - } -} - -impl<Tag> From<Pointer<Tag>> for Scalar<Tag> { - #[inline(always)] - fn from(ptr: Pointer<Tag>) -> Self { - Scalar::Ptr(ptr) - } -} - -#[derive(Clone, Copy, Eq, PartialEq, RustcEncodable, RustcDecodable, HashStable, Hash)] -pub enum ScalarMaybeUndef<Tag = (), Id = AllocId> { - Scalar(Scalar<Tag, Id>), - Undef, -} - -impl<Tag> From<Scalar<Tag>> for ScalarMaybeUndef<Tag> { - #[inline(always)] - fn from(s: Scalar<Tag>) -> Self { - ScalarMaybeUndef::Scalar(s) - } -} - -impl<Tag> From<Pointer<Tag>> for ScalarMaybeUndef<Tag> { - #[inline(always)] - fn from(s: Pointer<Tag>) -> Self { - ScalarMaybeUndef::Scalar(s.into()) - } -} - -impl<Tag: fmt::Debug, Id: fmt::Debug> fmt::Debug for ScalarMaybeUndef<Tag, Id> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ScalarMaybeUndef::Undef => write!(f, "Undef"), - ScalarMaybeUndef::Scalar(s) => write!(f, "{:?}", s), - } - } -} - -impl<Tag> fmt::Display for ScalarMaybeUndef<Tag> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ScalarMaybeUndef::Undef => write!(f, "uninitialized bytes"), - ScalarMaybeUndef::Scalar(s) => write!(f, "{}", s), - } - } -} - -impl<'tcx, Tag> ScalarMaybeUndef<Tag> { - /// Erase the tag from the scalar, if any. - /// - /// Used by error reporting code to avoid having the error type depend on `Tag`. - #[inline] - pub fn erase_tag(self) -> ScalarMaybeUndef { - match self { - ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.erase_tag()), - ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef, - } - } - - #[inline] - pub fn not_undef(self) -> InterpResult<'static, Scalar<Tag>> { - match self { - ScalarMaybeUndef::Scalar(scalar) => Ok(scalar), - ScalarMaybeUndef::Undef => throw_unsup!(ReadUndefBytes(Size::ZERO)), - } - } - - /// Do not call this method! Use either `assert_bits` or `force_bits`. - #[inline(always)] - pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> { - self.not_undef()?.to_bits(target_size) - } - - #[inline(always)] - pub fn to_bool(self) -> InterpResult<'tcx, bool> { - self.not_undef()?.to_bool() - } - - #[inline(always)] - pub fn to_char(self) -> InterpResult<'tcx, char> { - self.not_undef()?.to_char() - } - - #[inline(always)] - pub fn to_f32(self) -> InterpResult<'tcx, Single> { - self.not_undef()?.to_f32() - } - - #[inline(always)] - pub fn to_f64(self) -> InterpResult<'tcx, Double> { - self.not_undef()?.to_f64() - } - - #[inline(always)] - pub fn to_u8(self) -> InterpResult<'tcx, u8> { - self.not_undef()?.to_u8() - } - - #[inline(always)] - pub fn to_u32(self) -> InterpResult<'tcx, u32> { - self.not_undef()?.to_u32() - } - - #[inline(always)] - pub fn to_u64(self) -> InterpResult<'tcx, u64> { - self.not_undef()?.to_u64() - } - - #[inline(always)] - pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { - self.not_undef()?.to_machine_usize(cx) - } - - #[inline(always)] - pub fn to_i8(self) -> InterpResult<'tcx, i8> { - self.not_undef()?.to_i8() - } - - #[inline(always)] - pub fn to_i32(self) -> InterpResult<'tcx, i32> { - self.not_undef()?.to_i32() - } - - #[inline(always)] - pub fn to_i64(self) -> InterpResult<'tcx, i64> { - self.not_undef()?.to_i64() - } - - #[inline(always)] - pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> { - self.not_undef()?.to_machine_isize(cx) - } -} - -/// Gets the bytes of a constant slice value. -pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] { - if let ConstValue::Slice { data, start, end } = val { - let len = end - start; - data.get_bytes( - cx, - // invent a pointer, only the offset is relevant anyway - Pointer::new(AllocId(0), Size::from_bytes(start as u64)), - Size::from_bytes(len as u64), - ) - .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err)) - } else { - bug!("expected const slice, but found another const value"); - } -} diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs deleted file mode 100644 index 3086f9b04df..00000000000 --- a/src/librustc/mir/mod.rs +++ /dev/null @@ -1,2995 +0,0 @@ -//! MIR datatypes and passes. See the [rustc guide] for more info. -//! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/mir/index.html - -use crate::mir::interpret::{GlobalAlloc, Scalar}; -use crate::mir::visit::MirVisitable; -use crate::ty::adjustment::PointerCast; -use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use crate::ty::layout::VariantIdx; -use crate::ty::print::{FmtPrinter, Printer}; -use crate::ty::subst::{Subst, SubstsRef}; -use crate::ty::{ - self, AdtDef, CanonicalUserTypeAnnotations, List, Region, Ty, TyCtxt, UserTypeAnnotationIndex, -}; -use rustc_hir as hir; -use rustc_hir::def::{CtorKind, Namespace}; -use rustc_hir::def_id::DefId; -use rustc_hir::{self, GeneratorKind}; - -use polonius_engine::Atom; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::dominators::Dominators; -use rustc_data_structures::graph::{self, GraphSuccessors}; -use rustc_index::bit_set::BitMatrix; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_macros::HashStable; -use rustc_serialize::{Decodable, Encodable}; -use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; -use std::borrow::Cow; -use std::fmt::{self, Debug, Display, Formatter, Write}; -use std::ops::Index; -use std::slice; -use std::{iter, mem, option, u32}; -pub use syntax::ast::Mutability; -use syntax::ast::Name; - -pub use self::cache::{BodyAndCache, ReadOnlyBodyAndCache}; -pub use self::query::*; -pub use crate::read_only; - -mod cache; -pub mod interpret; -pub mod mono; -mod query; -pub mod tcx; -pub mod traversal; -pub mod visit; - -/// Types for locals -type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>; - -pub trait HasLocalDecls<'tcx> { - fn local_decls(&self) -> &LocalDecls<'tcx>; -} - -impl<'tcx> HasLocalDecls<'tcx> for LocalDecls<'tcx> { - fn local_decls(&self) -> &LocalDecls<'tcx> { - self - } -} - -impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { - fn local_decls(&self) -> &LocalDecls<'tcx> { - &self.local_decls - } -} - -/// The various "big phases" that MIR goes through. -/// -/// Warning: ordering of variants is significant. -#[derive( - Copy, - Clone, - RustcEncodable, - RustcDecodable, - HashStable, - Debug, - PartialEq, - Eq, - PartialOrd, - Ord -)] -pub enum MirPhase { - Build = 0, - Const = 1, - Validated = 2, - Optimized = 3, -} - -impl MirPhase { - /// Gets the index of the current MirPhase within the set of all `MirPhase`s. - pub fn phase_index(&self) -> usize { - *self as usize - } -} - -/// The lowered representation of a single function. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable, TypeFoldable)] -pub struct Body<'tcx> { - /// A list of basic blocks. References to basic block use a newtyped index type `BasicBlock` - /// that indexes into this vector. - basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, - - /// Records how far through the "desugaring and optimization" process this particular - /// MIR has traversed. This is particularly useful when inlining, since in that context - /// we instantiate the promoted constants and add them to our promoted vector -- but those - /// promoted items have already been optimized, whereas ours have not. This field allows - /// us to see the difference and forego optimization on the inlined promoted items. - pub phase: MirPhase, - - /// A list of source scopes; these are referenced by statements - /// and used for debuginfo. Indexed by a `SourceScope`. - pub source_scopes: IndexVec<SourceScope, SourceScopeData>, - - /// The yield type of the function, if it is a generator. - pub yield_ty: Option<Ty<'tcx>>, - - /// Generator drop glue. - pub generator_drop: Option<Box<BodyAndCache<'tcx>>>, - - /// The layout of a generator. Produced by the state transformation. - pub generator_layout: Option<GeneratorLayout<'tcx>>, - - /// If this is a generator then record the type of source expression that caused this generator - /// to be created. - pub generator_kind: Option<GeneratorKind>, - - /// Declarations of locals. - /// - /// The first local is the return value pointer, followed by `arg_count` - /// locals for the function arguments, followed by any user-declared - /// variables and temporaries. - pub local_decls: LocalDecls<'tcx>, - - /// User type annotations. - pub user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, - - /// The number of arguments this function takes. - /// - /// Starting at local 1, `arg_count` locals will be provided by the caller - /// and can be assumed to be initialized. - /// - /// If this MIR was built for a constant, this will be 0. - pub arg_count: usize, - - /// Mark an argument local (which must be a tuple) as getting passed as - /// its individual components at the LLVM level. - /// - /// This is used for the "rust-call" ABI. - pub spread_arg: Option<Local>, - - /// Debug information pertaining to user variables, including captures. - pub var_debug_info: Vec<VarDebugInfo<'tcx>>, - - /// Mark this MIR of a const context other than const functions as having converted a `&&` or - /// `||` expression into `&` or `|` respectively. This is problematic because if we ever stop - /// this conversion from happening and use short circuiting, we will cause the following code - /// to change the value of `x`: `let mut x = 42; false && { x = 55; true };` - /// - /// List of places where control flow was destroyed. Used for error reporting. - pub control_flow_destroyed: Vec<(Span, String)>, - - /// A span representing this MIR, for error reporting. - pub span: Span, - - /// The user may be writing e.g. &[(SOME_CELL, 42)][i].1 and this would get promoted, because - /// we'd statically know that no thing with interior mutability will ever be available to the - /// user without some serious unsafe code. Now this means that our promoted is actually - /// &[(SOME_CELL, 42)] and the MIR using it will do the &promoted[i].1 projection because the - /// index may be a runtime value. Such a promoted value is illegal because it has reachable - /// interior mutability. This flag just makes this situation very obvious where the previous - /// implementation without the flag hid this situation silently. - /// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components. - pub ignore_interior_mut_in_const_validation: bool, -} - -impl<'tcx> Body<'tcx> { - pub fn new( - basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, - source_scopes: IndexVec<SourceScope, SourceScopeData>, - local_decls: LocalDecls<'tcx>, - user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, - arg_count: usize, - var_debug_info: Vec<VarDebugInfo<'tcx>>, - span: Span, - control_flow_destroyed: Vec<(Span, String)>, - generator_kind: Option<GeneratorKind>, - ) -> Self { - // We need `arg_count` locals, and one for the return place. - assert!( - local_decls.len() >= arg_count + 1, - "expected at least {} locals, got {}", - arg_count + 1, - local_decls.len() - ); - - Body { - phase: MirPhase::Build, - basic_blocks, - source_scopes, - yield_ty: None, - generator_drop: None, - generator_layout: None, - generator_kind, - local_decls, - user_type_annotations, - arg_count, - spread_arg: None, - var_debug_info, - span, - ignore_interior_mut_in_const_validation: false, - control_flow_destroyed, - } - } - - /// Returns a partially initialized MIR body containing only a list of basic blocks. - /// - /// The returned MIR contains no `LocalDecl`s (even for the return place) or source scopes. It - /// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different - /// crate. - pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self { - Body { - phase: MirPhase::Build, - basic_blocks, - source_scopes: IndexVec::new(), - yield_ty: None, - generator_drop: None, - generator_layout: None, - local_decls: IndexVec::new(), - user_type_annotations: IndexVec::new(), - arg_count: 0, - spread_arg: None, - span: DUMMY_SP, - control_flow_destroyed: Vec::new(), - generator_kind: None, - var_debug_info: Vec::new(), - ignore_interior_mut_in_const_validation: false, - } - } - - #[inline] - pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> { - &self.basic_blocks - } - - /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the - /// `START_BLOCK`. - pub fn is_cfg_cyclic(&self) -> bool { - graph::is_cyclic(self) - } - - #[inline] - pub fn local_kind(&self, local: Local) -> LocalKind { - let index = local.as_usize(); - if index == 0 { - debug_assert!( - self.local_decls[local].mutability == Mutability::Mut, - "return place should be mutable" - ); - - LocalKind::ReturnPointer - } else if index < self.arg_count + 1 { - LocalKind::Arg - } else if self.local_decls[local].is_user_variable() { - LocalKind::Var - } else { - LocalKind::Temp - } - } - - /// Returns an iterator over all temporaries. - #[inline] - pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { - (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { - let local = Local::new(index); - if self.local_decls[local].is_user_variable() { None } else { Some(local) } - }) - } - - /// Returns an iterator over all user-declared locals. - #[inline] - pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { - (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { - let local = Local::new(index); - self.local_decls[local].is_user_variable().then_some(local) - }) - } - - /// Returns an iterator over all user-declared mutable locals. - #[inline] - pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { - (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { - let local = Local::new(index); - let decl = &self.local_decls[local]; - if decl.is_user_variable() && decl.mutability == Mutability::Mut { - Some(local) - } else { - None - } - }) - } - - /// Returns an iterator over all user-declared mutable arguments and locals. - #[inline] - pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { - (1..self.local_decls.len()).filter_map(move |index| { - let local = Local::new(index); - let decl = &self.local_decls[local]; - if (decl.is_user_variable() || index < self.arg_count + 1) - && decl.mutability == Mutability::Mut - { - Some(local) - } else { - None - } - }) - } - - /// Returns an iterator over all function arguments. - #[inline] - pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator { - let arg_count = self.arg_count; - (1..arg_count + 1).map(Local::new) - } - - /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all - /// locals that are neither arguments nor the return place). - #[inline] - pub fn vars_and_temps_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator { - let arg_count = self.arg_count; - let local_count = self.local_decls.len(); - (arg_count + 1..local_count).map(Local::new) - } - - /// Changes a statement to a nop. This is both faster than deleting instructions and avoids - /// invalidating statement indices in `Location`s. - pub fn make_statement_nop(&mut self, location: Location) { - let block = &mut self.basic_blocks[location.block]; - debug_assert!(location.statement_index < block.statements.len()); - block.statements[location.statement_index].make_nop() - } - - /// Returns the source info associated with `location`. - pub fn source_info(&self, location: Location) -> &SourceInfo { - let block = &self[location.block]; - let stmts = &block.statements; - let idx = location.statement_index; - if idx < stmts.len() { - &stmts[idx].source_info - } else { - assert_eq!(idx, stmts.len()); - &block.terminator().source_info - } - } - - /// Checks if `sub` is a sub scope of `sup` - pub fn is_sub_scope(&self, mut sub: SourceScope, sup: SourceScope) -> bool { - while sub != sup { - match self.source_scopes[sub].parent_scope { - None => return false, - Some(p) => sub = p, - } - } - true - } - - /// Returns the return type; it always return first element from `local_decls` array. - pub fn return_ty(&self) -> Ty<'tcx> { - self.local_decls[RETURN_PLACE].ty - } - - /// Gets the location of the terminator for the given block. - pub fn terminator_loc(&self, bb: BasicBlock) -> Location { - Location { block: bb, statement_index: self[bb].statements.len() } - } -} - -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub enum Safety { - Safe, - /// Unsafe because of a PushUnsafeBlock - BuiltinUnsafe, - /// Unsafe because of an unsafe fn - FnUnsafe, - /// Unsafe because of an `unsafe` block - ExplicitUnsafe(hir::HirId), -} - -impl<'tcx> Index<BasicBlock> for Body<'tcx> { - type Output = BasicBlockData<'tcx>; - - #[inline] - fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { - &self.basic_blocks()[index] - } -} - -#[derive(Copy, Clone, Debug, HashStable, TypeFoldable)] -pub enum ClearCrossCrate<T> { - Clear, - Set(T), -} - -impl<T> ClearCrossCrate<T> { - pub fn as_ref(&'a self) -> ClearCrossCrate<&'a T> { - match self { - ClearCrossCrate::Clear => ClearCrossCrate::Clear, - ClearCrossCrate::Set(v) => ClearCrossCrate::Set(v), - } - } - - pub fn assert_crate_local(self) -> T { - match self { - ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"), - ClearCrossCrate::Set(v) => v, - } - } -} - -impl<T: Encodable> rustc_serialize::UseSpecializedEncodable for ClearCrossCrate<T> {} -impl<T: Decodable> rustc_serialize::UseSpecializedDecodable for ClearCrossCrate<T> {} - -/// Grouped information about the source code origin of a MIR entity. -/// Intended to be inspected by diagnostics and debuginfo. -/// Most passes can work with it as a whole, within a single function. -// The unofficial Cranelift backend, at least as of #65828, needs `SourceInfo` to implement `Eq` and -// `Hash`. Please ping @bjorn3 if removing them. -#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash, HashStable)] -pub struct SourceInfo { - /// The source span for the AST pertaining to this MIR entity. - pub span: Span, - - /// The source scope, keeping track of which bindings can be - /// seen by debuginfo, active lint levels, `unsafe {...}`, etc. - pub scope: SourceScope, -} - -/////////////////////////////////////////////////////////////////////////// -// Borrow kinds - -#[derive( - Copy, - Clone, - Debug, - PartialEq, - Eq, - PartialOrd, - Ord, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub enum BorrowKind { - /// Data must be immutable and is aliasable. - Shared, - - /// The immediately borrowed place must be immutable, but projections from - /// it don't need to be. For example, a shallow borrow of `a.b` doesn't - /// conflict with a mutable borrow of `a.b.c`. - /// - /// This is used when lowering matches: when matching on a place we want to - /// ensure that place have the same value from the start of the match until - /// an arm is selected. This prevents this code from compiling: - /// - /// let mut x = &Some(0); - /// match *x { - /// None => (), - /// Some(_) if { x = &None; false } => (), - /// Some(_) => (), - /// } - /// - /// This can't be a shared borrow because mutably borrowing (*x as Some).0 - /// should not prevent `if let None = x { ... }`, for example, because the - /// mutating `(*x as Some).0` can't affect the discriminant of `x`. - /// We can also report errors with this kind of borrow differently. - Shallow, - - /// Data must be immutable but not aliasable. This kind of borrow - /// cannot currently be expressed by the user and is used only in - /// implicit closure bindings. It is needed when the closure is - /// borrowing or mutating a mutable referent, e.g.: - /// - /// let x: &mut isize = ...; - /// let y = || *x += 5; - /// - /// If we were to try to translate this closure into a more explicit - /// form, we'd encounter an error with the code as written: - /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } - /// - /// This is then illegal because you cannot mutate an `&mut` found - /// in an aliasable location. To solve, you'd have to translate with - /// an `&mut` borrow: - /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } - /// - /// Now the assignment to `**env.x` is legal, but creating a - /// mutable pointer to `x` is not because `x` is not mutable. We - /// could fix this by declaring `x` as `let mut x`. This is ok in - /// user code, if awkward, but extra weird for closures, since the - /// borrow is hidden. - /// - /// So we introduce a "unique imm" borrow -- the referent is - /// immutable, but not aliasable. This solves the problem. For - /// simplicity, we don't give users the way to express this - /// borrow, it's just used when translating closures. - Unique, - - /// Data is mutable and not aliasable. - Mut { - /// `true` if this borrow arose from method-call auto-ref - /// (i.e., `adjustment::Adjust::Borrow`). - allow_two_phase_borrow: bool, - }, -} - -impl BorrowKind { - pub fn allows_two_phase_borrow(&self) -> bool { - match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, - BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Variables and temps - -rustc_index::newtype_index! { - pub struct Local { - derive [HashStable] - DEBUG_FORMAT = "_{}", - const RETURN_PLACE = 0, - } -} - -impl Atom for Local { - fn index(self) -> usize { - Idx::index(self) - } -} - -/// Classifies locals into categories. See `Body::local_kind`. -#[derive(PartialEq, Eq, Debug, HashStable)] -pub enum LocalKind { - /// User-declared variable binding. - Var, - /// Compiler-introduced temporary. - Temp, - /// Function argument. - Arg, - /// Location of function's return value. - ReturnPointer, -} - -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct VarBindingForm<'tcx> { - /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`? - pub binding_mode: ty::BindingMode, - /// If an explicit type was provided for this variable binding, - /// this holds the source Span of that type. - /// - /// NOTE: if you want to change this to a `HirId`, be wary that - /// doing so breaks incremental compilation (as of this writing), - /// while a `Span` does not cause our tests to fail. - pub opt_ty_info: Option<Span>, - /// Place of the RHS of the =, or the subject of the `match` where this - /// variable is initialized. None in the case of `let PATTERN;`. - /// Some((None, ..)) in the case of and `let [mut] x = ...` because - /// (a) the right-hand side isn't evaluated as a place expression. - /// (b) it gives a way to separate this case from the remaining cases - /// for diagnostics. - pub opt_match_place: Option<(Option<Place<'tcx>>, Span)>, - /// The span of the pattern in which this variable was bound. - pub pat_span: Span, -} - -#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub enum BindingForm<'tcx> { - /// This is a binding for a non-`self` binding, or a `self` that has an explicit type. - Var(VarBindingForm<'tcx>), - /// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit. - ImplicitSelf(ImplicitSelfKind), - /// Reference used in a guard expression to ensure immutability. - RefForGuard, -} - -/// Represents what type of implicit self a function has, if any. -#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub enum ImplicitSelfKind { - /// Represents a `fn x(self);`. - Imm, - /// Represents a `fn x(mut self);`. - Mut, - /// Represents a `fn x(&self);`. - ImmRef, - /// Represents a `fn x(&mut self);`. - MutRef, - /// Represents when a function does not have a self argument or - /// when a function has a `self: X` argument. - None, -} - -CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } - -mod binding_form_impl { - use crate::ich::StableHashingContext; - use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - - impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use super::BindingForm::*; - ::std::mem::discriminant(self).hash_stable(hcx, hasher); - - match self { - Var(binding) => binding.hash_stable(hcx, hasher), - ImplicitSelf(kind) => kind.hash_stable(hcx, hasher), - RefForGuard => (), - } - } - } -} - -/// `BlockTailInfo` is attached to the `LocalDecl` for temporaries -/// created during evaluation of expressions in a block tail -/// expression; that is, a block like `{ STMT_1; STMT_2; EXPR }`. -/// -/// It is used to improve diagnostics when such temporaries are -/// involved in borrow_check errors, e.g., explanations of where the -/// temporaries come from, when their destructors are run, and/or how -/// one might revise the code to satisfy the borrow checker's rules. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct BlockTailInfo { - /// If `true`, then the value resulting from evaluating this tail - /// expression is ignored by the block's expression context. - /// - /// Examples include `{ ...; tail };` and `let _ = { ...; tail };` - /// but not e.g., `let _x = { ...; tail };` - pub tail_result_is_ignored: bool, -} - -/// A MIR local. -/// -/// This can be a binding declared by the user, a temporary inserted by the compiler, a function -/// argument, or the return place. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct LocalDecl<'tcx> { - /// Whether this is a mutable minding (i.e., `let x` or `let mut x`). - /// - /// Temporaries and the return place are always mutable. - pub mutability: Mutability, - - // FIXME(matthewjasper) Don't store in this in `Body` - pub local_info: LocalInfo<'tcx>, - - /// `true` if this is an internal local. - /// - /// These locals are not based on types in the source code and are only used - /// for a few desugarings at the moment. - /// - /// The generator transformation will sanity check the locals which are live - /// across a suspension point against the type components of the generator - /// which type checking knows are live across a suspension point. We need to - /// flag drop flags to avoid triggering this check as they are introduced - /// after typeck. - /// - /// Unsafety checking will also ignore dereferences of these locals, - /// so they can be used for raw pointers only used in a desugaring. - /// - /// This should be sound because the drop flags are fully algebraic, and - /// therefore don't affect the OIBIT or outlives properties of the - /// generator. - pub internal: bool, - - /// If this local is a temporary and `is_block_tail` is `Some`, - /// then it is a temporary created for evaluation of some - /// subexpression of some block's tail expression (with no - /// intervening statement context). - // FIXME(matthewjasper) Don't store in this in `Body` - pub is_block_tail: Option<BlockTailInfo>, - - /// The type of this local. - pub ty: Ty<'tcx>, - - /// If the user manually ascribed a type to this variable, - /// e.g., via `let x: T`, then we carry that type here. The MIR - /// borrow checker needs this information since it can affect - /// region inference. - // FIXME(matthewjasper) Don't store in this in `Body` - pub user_ty: UserTypeProjections, - - /// The *syntactic* (i.e., not visibility) source scope the local is defined - /// in. If the local was defined in a let-statement, this - /// is *within* the let-statement, rather than outside - /// of it. - /// - /// This is needed because the visibility source scope of locals within - /// a let-statement is weird. - /// - /// The reason is that we want the local to be *within* the let-statement - /// for lint purposes, but we want the local to be *after* the let-statement - /// for names-in-scope purposes. - /// - /// That's it, if we have a let-statement like the one in this - /// function: - /// - /// ``` - /// fn foo(x: &str) { - /// #[allow(unused_mut)] - /// let mut x: u32 = { // <- one unused mut - /// let mut y: u32 = x.parse().unwrap(); - /// y + 2 - /// }; - /// drop(x); - /// } - /// ``` - /// - /// Then, from a lint point of view, the declaration of `x: u32` - /// (and `y: u32`) are within the `#[allow(unused_mut)]` scope - the - /// lint scopes are the same as the AST/HIR nesting. - /// - /// However, from a name lookup point of view, the scopes look more like - /// as if the let-statements were `match` expressions: - /// - /// ``` - /// fn foo(x: &str) { - /// match { - /// match x.parse().unwrap() { - /// y => y + 2 - /// } - /// } { - /// x => drop(x) - /// }; - /// } - /// ``` - /// - /// We care about the name-lookup scopes for debuginfo - if the - /// debuginfo instruction pointer is at the call to `x.parse()`, we - /// want `x` to refer to `x: &str`, but if it is at the call to - /// `drop(x)`, we want it to refer to `x: u32`. - /// - /// To allow both uses to work, we need to have more than a single scope - /// for a local. We have the `source_info.scope` represent the "syntactic" - /// lint scope (with a variable being under its let block) while the - /// `var_debug_info.source_info.scope` represents the "local variable" - /// scope (where the "rest" of a block is under all prior let-statements). - /// - /// The end result looks like this: - /// - /// ```text - /// ROOT SCOPE - /// │{ argument x: &str } - /// │ - /// │ │{ #[allow(unused_mut)] } // This is actually split into 2 scopes - /// │ │ // in practice because I'm lazy. - /// │ │ - /// │ │← x.source_info.scope - /// │ │← `x.parse().unwrap()` - /// │ │ - /// │ │ │← y.source_info.scope - /// │ │ - /// │ │ │{ let y: u32 } - /// │ │ │ - /// │ │ │← y.var_debug_info.source_info.scope - /// │ │ │← `y + 2` - /// │ - /// │ │{ let x: u32 } - /// │ │← x.var_debug_info.source_info.scope - /// │ │← `drop(x)` // This accesses `x: u32`. - /// ``` - pub source_info: SourceInfo, -} - -/// Extra information about a local that's used for diagnostics. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub enum LocalInfo<'tcx> { - /// A user-defined local variable or function parameter - /// - /// The `BindingForm` is solely used for local diagnostics when generating - /// warnings/errors when compiling the current crate, and therefore it need - /// not be visible across crates. - User(ClearCrossCrate<BindingForm<'tcx>>), - /// A temporary created that references the static with the given `DefId`. - StaticRef { def_id: DefId, is_thread_local: bool }, - /// Any other temporary, the return place, or an anonymous function parameter. - Other, -} - -impl<'tcx> LocalDecl<'tcx> { - /// Returns `true` only if local is a binding that can itself be - /// made mutable via the addition of the `mut` keyword, namely - /// something like the occurrences of `x` in: - /// - `fn foo(x: Type) { ... }`, - /// - `let x = ...`, - /// - or `match ... { C(x) => ... }` - pub fn can_be_made_mutable(&self) -> bool { - match self.local_info { - LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(_), - opt_ty_info: _, - opt_match_place: _, - pat_span: _, - }))) => true, - - LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf( - ImplicitSelfKind::Imm, - ))) => true, - - _ => false, - } - } - - /// Returns `true` if local is definitely not a `ref ident` or - /// `ref mut ident` binding. (Such bindings cannot be made into - /// mutable bindings, but the inverse does not necessarily hold). - pub fn is_nonref_binding(&self) -> bool { - match self.local_info { - LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(_), - opt_ty_info: _, - opt_match_place: _, - pat_span: _, - }))) => true, - - LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true, - - _ => false, - } - } - - /// Returns `true` if this variable is a named variable or function - /// parameter declared by the user. - #[inline] - pub fn is_user_variable(&self) -> bool { - match self.local_info { - LocalInfo::User(_) => true, - _ => false, - } - } - - /// Returns `true` if this is a reference to a variable bound in a `match` - /// expression that is used to access said variable for the guard of the - /// match arm. - pub fn is_ref_for_guard(&self) -> bool { - match self.local_info { - LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)) => true, - _ => false, - } - } - - /// Returns `Some` if this is a reference to a static item that is used to - /// access that static - pub fn is_ref_to_static(&self) -> bool { - match self.local_info { - LocalInfo::StaticRef { .. } => true, - _ => false, - } - } - - /// Returns `Some` if this is a reference to a static item that is used to - /// access that static - pub fn is_ref_to_thread_local(&self) -> bool { - match self.local_info { - LocalInfo::StaticRef { is_thread_local, .. } => is_thread_local, - _ => false, - } - } - - /// Returns `true` is the local is from a compiler desugaring, e.g., - /// `__next` from a `for` loop. - #[inline] - pub fn from_compiler_desugaring(&self) -> bool { - self.source_info.span.desugaring_kind().is_some() - } - - /// Creates a new `LocalDecl` for a temporary. - #[inline] - pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self { - Self::new_local(ty, Mutability::Mut, false, span) - } - - /// Converts `self` into same `LocalDecl` except tagged as immutable. - #[inline] - pub fn immutable(mut self) -> Self { - self.mutability = Mutability::Not; - self - } - - /// Converts `self` into same `LocalDecl` except tagged as internal temporary. - #[inline] - pub fn block_tail(mut self, info: BlockTailInfo) -> Self { - assert!(self.is_block_tail.is_none()); - self.is_block_tail = Some(info); - self - } - - /// Creates a new `LocalDecl` for a internal temporary. - #[inline] - pub fn new_internal(ty: Ty<'tcx>, span: Span) -> Self { - Self::new_local(ty, Mutability::Mut, true, span) - } - - #[inline] - fn new_local(ty: Ty<'tcx>, mutability: Mutability, internal: bool, span: Span) -> Self { - LocalDecl { - mutability, - ty, - user_ty: UserTypeProjections::none(), - source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }, - internal, - local_info: LocalInfo::Other, - is_block_tail: None, - } - } - - /// Builds a `LocalDecl` for the return place. - /// - /// This must be inserted into the `local_decls` list as the first local. - #[inline] - pub fn new_return_place(return_ty: Ty<'_>, span: Span) -> LocalDecl<'_> { - LocalDecl { - mutability: Mutability::Mut, - ty: return_ty, - user_ty: UserTypeProjections::none(), - source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }, - internal: false, - is_block_tail: None, - local_info: LocalInfo::Other, - } - } -} - -/// Debug information pertaining to a user variable. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VarDebugInfo<'tcx> { - pub name: Name, - - /// Source info of the user variable, including the scope - /// within which the variable is visible (to debuginfo) - /// (see `LocalDecl`'s `source_info` field for more details). - pub source_info: SourceInfo, - - /// Where the data for this user variable is to be found. - /// NOTE(eddyb) There's an unenforced invariant that this `Place` is - /// based on a `Local`, not a `Static`, and contains no indexing. - pub place: Place<'tcx>, -} - -/////////////////////////////////////////////////////////////////////////// -// BasicBlock - -rustc_index::newtype_index! { - pub struct BasicBlock { - derive [HashStable] - DEBUG_FORMAT = "bb{}", - const START_BLOCK = 0, - } -} - -impl BasicBlock { - pub fn start_location(self) -> Location { - Location { block: self, statement_index: 0 } - } -} - -/////////////////////////////////////////////////////////////////////////// -// BasicBlockData and Terminator - -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct BasicBlockData<'tcx> { - /// List of statements in this block. - pub statements: Vec<Statement<'tcx>>, - - /// Terminator for this block. - /// - /// N.B., this should generally ONLY be `None` during construction. - /// Therefore, you should generally access it via the - /// `terminator()` or `terminator_mut()` methods. The only - /// exception is that certain passes, such as `simplify_cfg`, swap - /// out the terminator temporarily with `None` while they continue - /// to recurse over the set of basic blocks. - pub terminator: Option<Terminator<'tcx>>, - - /// If true, this block lies on an unwind path. This is used - /// during codegen where distinct kinds of basic blocks may be - /// generated (particularly for MSVC cleanup). Unwind blocks must - /// only branch to other unwind blocks. - pub is_cleanup: bool, -} - -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct Terminator<'tcx> { - pub source_info: SourceInfo, - pub kind: TerminatorKind<'tcx>, -} - -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)] -pub enum TerminatorKind<'tcx> { - /// Block should have one successor in the graph; we jump there. - Goto { target: BasicBlock }, - - /// Operand evaluates to an integer; jump depending on its value - /// to one of the targets, and otherwise fallback to `otherwise`. - SwitchInt { - /// The discriminant value being tested. - discr: Operand<'tcx>, - - /// The type of value being tested. - switch_ty: Ty<'tcx>, - - /// Possible values. The locations to branch to in each case - /// are found in the corresponding indices from the `targets` vector. - values: Cow<'tcx, [u128]>, - - /// Possible branch sites. The last element of this vector is used - /// for the otherwise branch, so targets.len() == values.len() + 1 - /// should hold. - // - // This invariant is quite non-obvious and also could be improved. - // One way to make this invariant is to have something like this instead: - // - // branches: Vec<(ConstInt, BasicBlock)>, - // otherwise: Option<BasicBlock> // exhaustive if None - // - // However we’ve decided to keep this as-is until we figure a case - // where some other approach seems to be strictly better than other. - targets: Vec<BasicBlock>, - }, - - /// Indicates that the landing pad is finished and unwinding should - /// continue. Emitted by `build::scope::diverge_cleanup`. - Resume, - - /// Indicates that the landing pad is finished and that the process - /// should abort. Used to prevent unwinding for foreign items. - Abort, - - /// Indicates a normal return. The return place should have - /// been filled in by now. This should occur at most once. - Return, - - /// Indicates a terminator that can never be reached. - Unreachable, - - /// Drop the `Place`. - Drop { location: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> }, - - /// Drop the `Place` and assign the new value over it. This ensures - /// that the assignment to `P` occurs *even if* the destructor for - /// place unwinds. Its semantics are best explained by the - /// elaboration: - /// - /// ``` - /// BB0 { - /// DropAndReplace(P <- V, goto BB1, unwind BB2) - /// } - /// ``` - /// - /// becomes - /// - /// ``` - /// BB0 { - /// Drop(P, goto BB1, unwind BB2) - /// } - /// BB1 { - /// // P is now uninitialized - /// P <- V - /// } - /// BB2 { - /// // P is now uninitialized -- its dtor panicked - /// P <- V - /// } - /// ``` - DropAndReplace { - location: Place<'tcx>, - value: Operand<'tcx>, - target: BasicBlock, - unwind: Option<BasicBlock>, - }, - - /// Block ends with a call of a converging function. - Call { - /// The function that’s being called. - func: Operand<'tcx>, - /// Arguments the function is called with. - /// These are owned by the callee, which is free to modify them. - /// This allows the memory occupied by "by-value" arguments to be - /// reused across function calls without duplicating the contents. - args: Vec<Operand<'tcx>>, - /// Destination for the return value. If some, the call is converging. - destination: Option<(Place<'tcx>, BasicBlock)>, - /// Cleanups to be done if the call unwinds. - cleanup: Option<BasicBlock>, - /// `true` if this is from a call in HIR rather than from an overloaded - /// operator. True for overloaded function call. - from_hir_call: bool, - }, - - /// Jump to the target if the condition has the expected value, - /// otherwise panic with a message and a cleanup target. - Assert { - cond: Operand<'tcx>, - expected: bool, - msg: AssertMessage<'tcx>, - target: BasicBlock, - cleanup: Option<BasicBlock>, - }, - - /// A suspend point. - Yield { - /// The value to return. - value: Operand<'tcx>, - /// Where to resume to. - resume: BasicBlock, - /// The place to store the resume argument in. - resume_arg: Place<'tcx>, - /// Cleanup to be done if the generator is dropped at this suspend point. - drop: Option<BasicBlock>, - }, - - /// Indicates the end of the dropping of a generator. - GeneratorDrop, - - /// A block where control flow only ever takes one real path, but borrowck - /// needs to be more conservative. - FalseEdges { - /// The target normal control flow will take. - real_target: BasicBlock, - /// A block control flow could conceptually jump to, but won't in - /// practice. - imaginary_target: BasicBlock, - }, - /// A terminator for blocks that only take one path in reality, but where we - /// reserve the right to unwind in borrowck, even if it won't happen in practice. - /// This can arise in infinite loops with no function calls for example. - FalseUnwind { - /// The target normal control flow will take. - real_target: BasicBlock, - /// The imaginary cleanup block link. This particular path will never be taken - /// in practice, but in order to avoid fragility we want to always - /// consider it in borrowck. We don't want to accept programs which - /// pass borrowck only when `panic=abort` or some assertions are disabled - /// due to release vs. debug mode builds. This needs to be an `Option` because - /// of the `remove_noop_landing_pads` and `no_landing_pads` passes. - unwind: Option<BasicBlock>, - }, -} - -/// Information about an assertion failure. -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)] -pub enum AssertKind<O> { - BoundsCheck { len: O, index: O }, - Overflow(BinOp), - OverflowNeg, - DivisionByZero, - RemainderByZero, - ResumedAfterReturn(GeneratorKind), - ResumedAfterPanic(GeneratorKind), -} - -/// Type for MIR `Assert` terminator error messages. -pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>; - -pub type Successors<'a> = - iter::Chain<option::IntoIter<&'a BasicBlock>, slice::Iter<'a, BasicBlock>>; -pub type SuccessorsMut<'a> = - iter::Chain<option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>; - -impl<'tcx> Terminator<'tcx> { - pub fn successors(&self) -> Successors<'_> { - self.kind.successors() - } - - pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { - self.kind.successors_mut() - } - - pub fn unwind(&self) -> Option<&Option<BasicBlock>> { - self.kind.unwind() - } - - pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> { - self.kind.unwind_mut() - } -} - -impl<'tcx> TerminatorKind<'tcx> { - pub fn if_( - tcx: TyCtxt<'tcx>, - cond: Operand<'tcx>, - t: BasicBlock, - f: BasicBlock, - ) -> TerminatorKind<'tcx> { - static BOOL_SWITCH_FALSE: &'static [u128] = &[0]; - TerminatorKind::SwitchInt { - discr: cond, - switch_ty: tcx.types.bool, - values: From::from(BOOL_SWITCH_FALSE), - targets: vec![f, t], - } - } - - pub fn successors(&self) -> Successors<'_> { - use self::TerminatorKind::*; - match *self { - Resume - | Abort - | GeneratorDrop - | Return - | Unreachable - | Call { destination: None, cleanup: None, .. } => None.into_iter().chain(&[]), - Goto { target: ref t } - | Call { destination: None, cleanup: Some(ref t), .. } - | Call { destination: Some((_, ref t)), cleanup: None, .. } - | Yield { resume: ref t, drop: None, .. } - | DropAndReplace { target: ref t, unwind: None, .. } - | Drop { target: ref t, unwind: None, .. } - | Assert { target: ref t, cleanup: None, .. } - | FalseUnwind { real_target: ref t, unwind: None } => Some(t).into_iter().chain(&[]), - Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. } - | Yield { resume: ref t, drop: Some(ref u), .. } - | DropAndReplace { target: ref t, unwind: Some(ref u), .. } - | Drop { target: ref t, unwind: Some(ref u), .. } - | Assert { target: ref t, cleanup: Some(ref u), .. } - | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => { - Some(t).into_iter().chain(slice::from_ref(u)) - } - SwitchInt { ref targets, .. } => None.into_iter().chain(&targets[..]), - FalseEdges { ref real_target, ref imaginary_target } => { - Some(real_target).into_iter().chain(slice::from_ref(imaginary_target)) - } - } - } - - pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { - use self::TerminatorKind::*; - match *self { - Resume - | Abort - | GeneratorDrop - | Return - | Unreachable - | Call { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []), - Goto { target: ref mut t } - | Call { destination: None, cleanup: Some(ref mut t), .. } - | Call { destination: Some((_, ref mut t)), cleanup: None, .. } - | Yield { resume: ref mut t, drop: None, .. } - | DropAndReplace { target: ref mut t, unwind: None, .. } - | Drop { target: ref mut t, unwind: None, .. } - | Assert { target: ref mut t, cleanup: None, .. } - | FalseUnwind { real_target: ref mut t, unwind: None } => { - Some(t).into_iter().chain(&mut []) - } - Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. } - | Yield { resume: ref mut t, drop: Some(ref mut u), .. } - | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. } - | Drop { target: ref mut t, unwind: Some(ref mut u), .. } - | Assert { target: ref mut t, cleanup: Some(ref mut u), .. } - | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => { - Some(t).into_iter().chain(slice::from_mut(u)) - } - SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets[..]), - FalseEdges { ref mut real_target, ref mut imaginary_target } => { - Some(real_target).into_iter().chain(slice::from_mut(imaginary_target)) - } - } - } - - pub fn unwind(&self) -> Option<&Option<BasicBlock>> { - match *self { - TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::GeneratorDrop - | TerminatorKind::Yield { .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::FalseEdges { .. } => None, - TerminatorKind::Call { cleanup: ref unwind, .. } - | TerminatorKind::Assert { cleanup: ref unwind, .. } - | TerminatorKind::DropAndReplace { ref unwind, .. } - | TerminatorKind::Drop { ref unwind, .. } - | TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind), - } - } - - pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> { - match *self { - TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::GeneratorDrop - | TerminatorKind::Yield { .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::FalseEdges { .. } => None, - TerminatorKind::Call { cleanup: ref mut unwind, .. } - | TerminatorKind::Assert { cleanup: ref mut unwind, .. } - | TerminatorKind::DropAndReplace { ref mut unwind, .. } - | TerminatorKind::Drop { ref mut unwind, .. } - | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind), - } - } -} - -impl<'tcx> BasicBlockData<'tcx> { - pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> { - BasicBlockData { statements: vec![], terminator, is_cleanup: false } - } - - /// Accessor for terminator. - /// - /// Terminator may not be None after construction of the basic block is complete. This accessor - /// provides a convenience way to reach the terminator. - pub fn terminator(&self) -> &Terminator<'tcx> { - self.terminator.as_ref().expect("invalid terminator state") - } - - pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> { - self.terminator.as_mut().expect("invalid terminator state") - } - - pub fn retain_statements<F>(&mut self, mut f: F) - where - F: FnMut(&mut Statement<'_>) -> bool, - { - for s in &mut self.statements { - if !f(s) { - s.make_nop(); - } - } - } - - pub fn expand_statements<F, I>(&mut self, mut f: F) - where - F: FnMut(&mut Statement<'tcx>) -> Option<I>, - I: iter::TrustedLen<Item = Statement<'tcx>>, - { - // Gather all the iterators we'll need to splice in, and their positions. - let mut splices: Vec<(usize, I)> = vec![]; - let mut extra_stmts = 0; - for (i, s) in self.statements.iter_mut().enumerate() { - if let Some(mut new_stmts) = f(s) { - if let Some(first) = new_stmts.next() { - // We can already store the first new statement. - *s = first; - - // Save the other statements for optimized splicing. - let remaining = new_stmts.size_hint().0; - if remaining > 0 { - splices.push((i + 1 + extra_stmts, new_stmts)); - extra_stmts += remaining; - } - } else { - s.make_nop(); - } - } - } - - // Splice in the new statements, from the end of the block. - // FIXME(eddyb) This could be more efficient with a "gap buffer" - // where a range of elements ("gap") is left uninitialized, with - // splicing adding new elements to the end of that gap and moving - // existing elements from before the gap to the end of the gap. - // For now, this is safe code, emulating a gap but initializing it. - let mut gap = self.statements.len()..self.statements.len() + extra_stmts; - self.statements.resize( - gap.end, - Statement { - source_info: SourceInfo { span: DUMMY_SP, scope: OUTERMOST_SOURCE_SCOPE }, - kind: StatementKind::Nop, - }, - ); - for (splice_start, new_stmts) in splices.into_iter().rev() { - let splice_end = splice_start + new_stmts.size_hint().0; - while gap.end > splice_end { - gap.start -= 1; - gap.end -= 1; - self.statements.swap(gap.start, gap.end); - } - self.statements.splice(splice_start..splice_end, new_stmts); - gap.end = splice_start; - } - } - - pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> { - if index < self.statements.len() { &self.statements[index] } else { &self.terminator } - } -} - -impl<O> AssertKind<O> { - /// Getting a description does not require `O` to be printable, and does not - /// require allocation. - /// The caller is expected to handle `BoundsCheck` separately. - pub fn description(&self) -> &'static str { - use AssertKind::*; - match self { - Overflow(BinOp::Add) => "attempt to add with overflow", - Overflow(BinOp::Sub) => "attempt to subtract with overflow", - Overflow(BinOp::Mul) => "attempt to multiply with overflow", - Overflow(BinOp::Div) => "attempt to divide with overflow", - Overflow(BinOp::Rem) => "attempt to calculate the remainder with overflow", - OverflowNeg => "attempt to negate with overflow", - Overflow(BinOp::Shr) => "attempt to shift right with overflow", - Overflow(BinOp::Shl) => "attempt to shift left with overflow", - Overflow(op) => bug!("{:?} cannot overflow", op), - DivisionByZero => "attempt to divide by zero", - RemainderByZero => "attempt to calculate the remainder with a divisor of zero", - ResumedAfterReturn(GeneratorKind::Gen) => "generator resumed after completion", - ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion", - ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking", - ResumedAfterPanic(GeneratorKind::Async(_)) => "`async fn` resumed after panicking", - BoundsCheck { .. } => bug!("Unexpected AssertKind"), - } - } -} - -impl<O: fmt::Debug> fmt::Debug for AssertKind<O> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use AssertKind::*; - match self { - BoundsCheck { ref len, ref index } => { - write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index) - } - _ => write!(f, "{}", self.description()), - } - } -} - -impl<'tcx> Debug for TerminatorKind<'tcx> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - self.fmt_head(fmt)?; - let successor_count = self.successors().count(); - let labels = self.fmt_successor_labels(); - assert_eq!(successor_count, labels.len()); - - match successor_count { - 0 => Ok(()), - - 1 => write!(fmt, " -> {:?}", self.successors().nth(0).unwrap()), - - _ => { - write!(fmt, " -> [")?; - for (i, target) in self.successors().enumerate() { - if i > 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{}: {:?}", labels[i], target)?; - } - write!(fmt, "]") - } - } - } -} - -impl<'tcx> TerminatorKind<'tcx> { - /// Writes the "head" part of the terminator; that is, its name and the data it uses to pick the - /// successor basic block, if any. The only information not included is the list of possible - /// successors, which may be rendered differently between the text and the graphviz format. - pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result { - use self::TerminatorKind::*; - match self { - Goto { .. } => write!(fmt, "goto"), - SwitchInt { discr, .. } => write!(fmt, "switchInt({:?})", discr), - Return => write!(fmt, "return"), - GeneratorDrop => write!(fmt, "generator_drop"), - Resume => write!(fmt, "resume"), - Abort => write!(fmt, "abort"), - Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value), - Unreachable => write!(fmt, "unreachable"), - Drop { location, .. } => write!(fmt, "drop({:?})", location), - DropAndReplace { location, value, .. } => { - write!(fmt, "replace({:?} <- {:?})", location, value) - } - Call { func, args, destination, .. } => { - if let Some((destination, _)) = destination { - write!(fmt, "{:?} = ", destination)?; - } - write!(fmt, "{:?}(", func)?; - for (index, arg) in args.iter().enumerate() { - if index > 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{:?}", arg)?; - } - write!(fmt, ")") - } - Assert { cond, expected, msg, .. } => { - write!(fmt, "assert(")?; - if !expected { - write!(fmt, "!")?; - } - write!(fmt, "{:?}, \"{:?}\")", cond, msg) - } - FalseEdges { .. } => write!(fmt, "falseEdges"), - FalseUnwind { .. } => write!(fmt, "falseUnwind"), - } - } - - /// Returns the list of labels for the edges to the successor basic blocks. - pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> { - use self::TerminatorKind::*; - match *self { - Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], - Goto { .. } => vec!["".into()], - SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| { - let param_env = ty::ParamEnv::empty(); - let switch_ty = tcx.lift(&switch_ty).unwrap(); - let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size; - values - .iter() - .map(|&u| { - ty::Const::from_scalar(tcx, Scalar::from_uint(u, size).into(), switch_ty) - .to_string() - .into() - }) - .chain(iter::once("otherwise".into())) - .collect() - }), - Call { destination: Some(_), cleanup: Some(_), .. } => { - vec!["return".into(), "unwind".into()] - } - Call { destination: Some(_), cleanup: None, .. } => vec!["return".into()], - Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()], - Call { destination: None, cleanup: None, .. } => vec![], - Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()], - Yield { drop: None, .. } => vec!["resume".into()], - DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => { - vec!["return".into()] - } - DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. } => { - vec!["return".into(), "unwind".into()] - } - Assert { cleanup: None, .. } => vec!["".into()], - Assert { .. } => vec!["success".into(), "unwind".into()], - FalseEdges { .. } => vec!["real".into(), "imaginary".into()], - FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()], - FalseUnwind { unwind: None, .. } => vec!["real".into()], - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Statements - -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct Statement<'tcx> { - pub source_info: SourceInfo, - pub kind: StatementKind<'tcx>, -} - -// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(target_arch = "x86_64")] -static_assert_size!(Statement<'_>, 32); - -impl Statement<'_> { - /// Changes a statement to a nop. This is both faster than deleting instructions and avoids - /// invalidating statement indices in `Location`s. - pub fn make_nop(&mut self) { - self.kind = StatementKind::Nop - } - - /// Changes a statement to a nop and returns the original statement. - pub fn replace_nop(&mut self) -> Self { - Statement { - source_info: self.source_info, - kind: mem::replace(&mut self.kind, StatementKind::Nop), - } - } -} - -#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub enum StatementKind<'tcx> { - /// Write the RHS Rvalue to the LHS Place. - Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>), - - /// This represents all the reading that a pattern match may do - /// (e.g., inspecting constants and discriminant values), and the - /// kind of pattern it comes from. This is in order to adapt potential - /// error messages to these specific patterns. - /// - /// Note that this also is emitted for regular `let` bindings to ensure that locals that are - /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;` - FakeRead(FakeReadCause, Box<Place<'tcx>>), - - /// Write the discriminant for a variant to the enum Place. - SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx }, - - /// Start a live range for the storage of the local. - StorageLive(Local), - - /// End the current live range for the storage of the local. - StorageDead(Local), - - /// Executes a piece of inline Assembly. Stored in a Box to keep the size - /// of `StatementKind` low. - InlineAsm(Box<InlineAsm<'tcx>>), - - /// Retag references in the given place, ensuring they got fresh tags. This is - /// part of the Stacked Borrows model. These statements are currently only interpreted - /// by miri and only generated when "-Z mir-emit-retag" is passed. - /// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> - /// for more details. - Retag(RetagKind, Box<Place<'tcx>>), - - /// Encodes a user's type ascription. These need to be preserved - /// intact so that NLL can respect them. For example: - /// - /// let a: T = y; - /// - /// The effect of this annotation is to relate the type `T_y` of the place `y` - /// to the user-given type `T`. The effect depends on the specified variance: - /// - /// - `Covariant` -- requires that `T_y <: T` - /// - `Contravariant` -- requires that `T_y :> T` - /// - `Invariant` -- requires that `T_y == T` - /// - `Bivariant` -- no effect - AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance), - - /// No-op. Useful for deleting instructions without affecting statement indices. - Nop, -} - -/// Describes what kind of retag is to be performed. -#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, HashStable)] -pub enum RetagKind { - /// The initial retag when entering a function. - FnEntry, - /// Retag preparing for a two-phase borrow. - TwoPhase, - /// Retagging raw pointers. - Raw, - /// A "normal" retag. - Default, -} - -/// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists. -#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable, PartialEq)] -pub enum FakeReadCause { - /// Inject a fake read of the borrowed input at the end of each guards - /// code. - /// - /// This should ensure that you cannot change the variant for an enum while - /// you are in the midst of matching on it. - ForMatchGuard, - - /// `let x: !; match x {}` doesn't generate any read of x so we need to - /// generate a read of x to check that it is initialized and safe. - ForMatchedPlace, - - /// A fake read of the RefWithinGuard version of a bind-by-value variable - /// in a match guard to ensure that it's value hasn't change by the time - /// we create the OutsideGuard version. - ForGuardBinding, - - /// Officially, the semantics of - /// - /// `let pattern = <expr>;` - /// - /// is that `<expr>` is evaluated into a temporary and then this temporary is - /// into the pattern. - /// - /// However, if we see the simple pattern `let var = <expr>`, we optimize this to - /// evaluate `<expr>` directly into the variable `var`. This is mostly unobservable, - /// but in some cases it can affect the borrow checker, as in #53695. - /// Therefore, we insert a "fake read" here to ensure that we get - /// appropriate errors. - ForLet, - - /// If we have an index expression like - /// - /// (*x)[1][{ x = y; 4}] - /// - /// then the first bounds check is invalidated when we evaluate the second - /// index expression. Thus we create a fake borrow of `x` across the second - /// indexer, which will cause a borrow check error. - ForIndex, -} - -#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct InlineAsm<'tcx> { - pub asm: hir::InlineAsmInner, - pub outputs: Box<[Place<'tcx>]>, - pub inputs: Box<[(Span, Operand<'tcx>)]>, -} - -impl Debug for Statement<'_> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - use self::StatementKind::*; - match self.kind { - Assign(box (ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv), - FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place), - Retag(ref kind, ref place) => write!( - fmt, - "Retag({}{:?})", - match kind { - RetagKind::FnEntry => "[fn entry] ", - RetagKind::TwoPhase => "[2phase] ", - RetagKind::Raw => "[raw] ", - RetagKind::Default => "", - }, - place, - ), - StorageLive(ref place) => write!(fmt, "StorageLive({:?})", place), - StorageDead(ref place) => write!(fmt, "StorageDead({:?})", place), - SetDiscriminant { ref place, variant_index } => { - write!(fmt, "discriminant({:?}) = {:?}", place, variant_index) - } - InlineAsm(ref asm) => { - write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs) - } - AscribeUserType(box (ref place, ref c_ty), ref variance) => { - write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) - } - Nop => write!(fmt, "nop"), - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Places - -/// A path to a value; something that can be evaluated without -/// changing or disturbing program state. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable)] -pub struct Place<'tcx> { - pub local: Local, - - /// projection out of a place (access a field, deref a pointer, etc) - pub projection: &'tcx List<PlaceElem<'tcx>>, -} - -impl<'tcx> rustc_serialize::UseSpecializedDecodable for Place<'tcx> {} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(RustcEncodable, RustcDecodable, HashStable)] -pub enum ProjectionElem<V, T> { - Deref, - Field(Field, T), - Index(V), - - /// These indices are generated by slice patterns. Easiest to explain - /// by example: - /// - /// ``` - /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, - /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, - /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, - /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, - /// ``` - ConstantIndex { - /// index or -index (in Python terms), depending on from_end - offset: u32, - /// The thing being indexed must be at least this long. For arrays this - /// is always the exact length. - min_length: u32, - /// Counting backwards from end? This is always false when indexing an - /// array. - from_end: bool, - }, - - /// These indices are generated by slice patterns. - /// - /// If `from_end` is true `slice[from..slice.len() - to]`. - /// Otherwise `array[from..to]`. - Subslice { - from: u32, - to: u32, - /// Whether `to` counts from the start or end of the array/slice. - /// For `PlaceElem`s this is `true` if and only if the base is a slice. - /// For `ProjectionKind`, this can also be `true` for arrays. - from_end: bool, - }, - - /// "Downcast" to a variant of an ADT. Currently, we only introduce - /// this for ADTs with more than one variant. It may be better to - /// just introduce it always, or always for enums. - /// - /// The included Symbol is the name of the variant, used for printing MIR. - Downcast(Option<Symbol>, VariantIdx), -} - -impl<V, T> ProjectionElem<V, T> { - /// Returns `true` if the target of this projection may refer to a different region of memory - /// than the base. - fn is_indirect(&self) -> bool { - match self { - Self::Deref => true, - - Self::Field(_, _) - | Self::Index(_) - | Self::ConstantIndex { .. } - | Self::Subslice { .. } - | Self::Downcast(_, _) => false, - } - } -} - -/// Alias for projections as they appear in places, where the base is a place -/// and the index is a local. -pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; - -impl<'tcx> Copy for PlaceElem<'tcx> {} - -// At least on 64 bit systems, `PlaceElem` should not be larger than two pointers. -#[cfg(target_arch = "x86_64")] -static_assert_size!(PlaceElem<'_>, 16); - -/// Alias for projections as they appear in `UserTypeProjection`, where we -/// need neither the `V` parameter for `Index` nor the `T` for `Field`. -pub type ProjectionKind = ProjectionElem<(), ()>; - -rustc_index::newtype_index! { - pub struct Field { - derive [HashStable] - DEBUG_FORMAT = "field[{}]" - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct PlaceRef<'a, 'tcx> { - pub local: Local, - pub projection: &'a [PlaceElem<'tcx>], -} - -impl<'tcx> Place<'tcx> { - // FIXME change this to a const fn by also making List::empty a const fn. - pub fn return_place() -> Place<'tcx> { - Place { local: RETURN_PLACE, projection: List::empty() } - } - - /// Returns `true` if this `Place` contains a `Deref` projection. - /// - /// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the - /// same region of memory as its base. - pub fn is_indirect(&self) -> bool { - self.projection.iter().any(|elem| elem.is_indirect()) - } - - /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or - /// a single deref of a local. - // - // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? - pub fn local_or_deref_local(&self) -> Option<Local> { - match self.as_ref() { - PlaceRef { local, projection: [] } - | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local), - _ => None, - } - } - - /// If this place represents a local variable like `_X` with no - /// projections, return `Some(_X)`. - pub fn as_local(&self) -> Option<Local> { - self.as_ref().as_local() - } - - pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> { - PlaceRef { local: self.local, projection: &self.projection } - } -} - -impl From<Local> for Place<'_> { - fn from(local: Local) -> Self { - Place { local, projection: List::empty() } - } -} - -impl<'a, 'tcx> PlaceRef<'a, 'tcx> { - /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or - /// a single deref of a local. - // - // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? - pub fn local_or_deref_local(&self) -> Option<Local> { - match *self { - PlaceRef { local, projection: [] } - | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local), - _ => None, - } - } - - /// If this place represents a local variable like `_X` with no - /// projections, return `Some(_X)`. - pub fn as_local(&self) -> Option<Local> { - match *self { - PlaceRef { local, projection: [] } => Some(local), - _ => None, - } - } -} - -impl Debug for Place<'_> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - for elem in self.projection.iter().rev() { - match elem { - ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { - write!(fmt, "(").unwrap(); - } - ProjectionElem::Deref => { - write!(fmt, "(*").unwrap(); - } - ProjectionElem::Index(_) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } => {} - } - } - - write!(fmt, "{:?}", self.local)?; - - for elem in self.projection.iter() { - match elem { - ProjectionElem::Downcast(Some(name), _index) => { - write!(fmt, " as {})", name)?; - } - ProjectionElem::Downcast(None, index) => { - write!(fmt, " as variant#{:?})", index)?; - } - ProjectionElem::Deref => { - write!(fmt, ")")?; - } - ProjectionElem::Field(field, ty) => { - write!(fmt, ".{:?}: {:?})", field.index(), ty)?; - } - ProjectionElem::Index(ref index) => { - write!(fmt, "[{:?}]", index)?; - } - ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => { - write!(fmt, "[{:?} of {:?}]", offset, min_length)?; - } - ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { - write!(fmt, "[-{:?} of {:?}]", offset, min_length)?; - } - ProjectionElem::Subslice { from, to, from_end: true } if *to == 0 => { - write!(fmt, "[{:?}:]", from)?; - } - ProjectionElem::Subslice { from, to, from_end: true } if *from == 0 => { - write!(fmt, "[:-{:?}]", to)?; - } - ProjectionElem::Subslice { from, to, from_end: true } => { - write!(fmt, "[{:?}:-{:?}]", from, to)?; - } - ProjectionElem::Subslice { from, to, from_end: false } => { - write!(fmt, "[{:?}..{:?}]", from, to)?; - } - } - } - - Ok(()) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Scopes - -rustc_index::newtype_index! { - pub struct SourceScope { - derive [HashStable] - DEBUG_FORMAT = "scope[{}]", - const OUTERMOST_SOURCE_SCOPE = 0, - } -} - -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct SourceScopeData { - pub span: Span, - pub parent_scope: Option<SourceScope>, - - /// Crate-local information for this source scope, that can't (and - /// needn't) be tracked across crates. - pub local_data: ClearCrossCrate<SourceScopeLocalData>, -} - -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct SourceScopeLocalData { - /// An `HirId` with lint levels equivalent to this scope's lint levels. - pub lint_root: hir::HirId, - /// The unsafe block that contains this node. - pub safety: Safety, -} - -/////////////////////////////////////////////////////////////////////////// -// Operands - -/// These are values that can appear inside an rvalue. They are intentionally -/// limited to prevent rvalues from being nested in one another. -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] -pub enum Operand<'tcx> { - /// Copy: The value must be available for use afterwards. - /// - /// This implies that the type of the place must be `Copy`; this is true - /// by construction during build, but also checked by the MIR type checker. - Copy(Place<'tcx>), - - /// Move: The value (including old borrows of it) will not be used again. - /// - /// Safe for values of all types (modulo future developments towards `?Move`). - /// Correct usage patterns are enforced by the borrow checker for safe code. - /// `Copy` may be converted to `Move` to enable "last-use" optimizations. - Move(Place<'tcx>), - - /// Synthesizes a constant value. - Constant(Box<Constant<'tcx>>), -} - -impl<'tcx> Debug for Operand<'tcx> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - use self::Operand::*; - match *self { - Constant(ref a) => write!(fmt, "{:?}", a), - Copy(ref place) => write!(fmt, "{:?}", place), - Move(ref place) => write!(fmt, "move {:?}", place), - } - } -} - -impl<'tcx> Operand<'tcx> { - /// Convenience helper to make a constant that refers to the fn - /// with given `DefId` and substs. Since this is used to synthesize - /// MIR, assumes `user_ty` is None. - pub fn function_handle( - tcx: TyCtxt<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, - span: Span, - ) -> Self { - let ty = tcx.type_of(def_id).subst(tcx, substs); - Operand::Constant(box Constant { - span, - user_ty: None, - literal: ty::Const::zero_sized(tcx, ty), - }) - } - - pub fn to_copy(&self) -> Self { - match *self { - Operand::Copy(_) | Operand::Constant(_) => self.clone(), - Operand::Move(place) => Operand::Copy(place), - } - } - - /// Returns the `Place` that is the target of this `Operand`, or `None` if this `Operand` is a - /// constant. - pub fn place(&self) -> Option<&Place<'tcx>> { - match self { - Operand::Copy(place) | Operand::Move(place) => Some(place), - Operand::Constant(_) => None, - } - } -} - -/////////////////////////////////////////////////////////////////////////// -/// Rvalues - -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)] -pub enum Rvalue<'tcx> { - /// x (either a move or copy, depending on type of x) - Use(Operand<'tcx>), - - /// [x; 32] - Repeat(Operand<'tcx>, u64), - - /// &x or &mut x - Ref(Region<'tcx>, BorrowKind, Place<'tcx>), - - /// Create a raw pointer to the given place - /// Can be generated by raw address of expressions (`&raw const x`), - /// or when casting a reference to a raw pointer. - AddressOf(Mutability, Place<'tcx>), - - /// length of a [X] or [X;n] value - Len(Place<'tcx>), - - Cast(CastKind, Operand<'tcx>, Ty<'tcx>), - - BinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), - CheckedBinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), - - NullaryOp(NullOp, Ty<'tcx>), - UnaryOp(UnOp, Operand<'tcx>), - - /// Read the discriminant of an ADT. - /// - /// Undefined (i.e., no effort is made to make it defined, but there’s no reason why it cannot - /// be defined to return, say, a 0) if ADT is not an enum. - Discriminant(Place<'tcx>), - - /// Creates an aggregate value, like a tuple or struct. This is - /// only needed because we want to distinguish `dest = Foo { x: - /// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case - /// that `Foo` has a destructor. These rvalues can be optimized - /// away after type-checking and before lowering. - Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>), -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] -pub enum CastKind { - Misc, - Pointer(PointerCast), -} - -#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] -pub enum AggregateKind<'tcx> { - /// The type is of the element - Array(Ty<'tcx>), - Tuple, - - /// The second field is the variant index. It's equal to 0 for struct - /// and union expressions. The fourth field is - /// active field number and is present only for union expressions - /// -- e.g., for a union expression `SomeUnion { c: .. }`, the - /// active field index would identity the field `c` - Adt(&'tcx AdtDef, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), - - Closure(DefId, SubstsRef<'tcx>), - Generator(DefId, SubstsRef<'tcx>, hir::Movability), -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] -pub enum BinOp { - /// The `+` operator (addition) - Add, - /// The `-` operator (subtraction) - Sub, - /// The `*` operator (multiplication) - Mul, - /// The `/` operator (division) - Div, - /// The `%` operator (modulus) - Rem, - /// The `^` operator (bitwise xor) - BitXor, - /// The `&` operator (bitwise and) - BitAnd, - /// The `|` operator (bitwise or) - BitOr, - /// The `<<` operator (shift left) - Shl, - /// The `>>` operator (shift right) - Shr, - /// The `==` operator (equality) - Eq, - /// The `<` operator (less than) - Lt, - /// The `<=` operator (less than or equal to) - Le, - /// The `!=` operator (not equal to) - Ne, - /// The `>=` operator (greater than or equal to) - Ge, - /// The `>` operator (greater than) - Gt, - /// The `ptr.offset` operator - Offset, -} - -impl BinOp { - pub fn is_checkable(self) -> bool { - use self::BinOp::*; - match self { - Add | Sub | Mul | Shl | Shr => true, - _ => false, - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] -pub enum NullOp { - /// Returns the size of a value of that type - SizeOf, - /// Creates a new uninitialized box for a value of that type - Box, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] -pub enum UnOp { - /// The `!` operator for logical inversion - Not, - /// The `-` operator for negation - Neg, -} - -impl<'tcx> Debug for Rvalue<'tcx> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - use self::Rvalue::*; - - match *self { - Use(ref place) => write!(fmt, "{:?}", place), - Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b), - Len(ref a) => write!(fmt, "Len({:?})", a), - Cast(ref kind, ref place, ref ty) => { - write!(fmt, "{:?} as {:?} ({:?})", place, ty, kind) - } - BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?}, {:?})", op, a, b), - CheckedBinaryOp(ref op, ref a, ref b) => { - write!(fmt, "Checked{:?}({:?}, {:?})", op, a, b) - } - UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), - Discriminant(ref place) => write!(fmt, "discriminant({:?})", place), - NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t), - Ref(region, borrow_kind, ref place) => { - let kind_str = match borrow_kind { - BorrowKind::Shared => "", - BorrowKind::Shallow => "shallow ", - BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ", - }; - - // When printing regions, add trailing space if necessary. - let print_region = ty::tls::with(|tcx| { - tcx.sess.verbose() || tcx.sess.opts.debugging_opts.identify_regions - }); - let region = if print_region { - let mut region = region.to_string(); - if region.len() > 0 { - region.push(' '); - } - region - } else { - // Do not even print 'static - String::new() - }; - write!(fmt, "&{}{}{:?}", region, kind_str, place) - } - - AddressOf(mutability, ref place) => { - let kind_str = match mutability { - Mutability::Mut => "mut", - Mutability::Not => "const", - }; - - write!(fmt, "&raw {} {:?}", kind_str, place) - } - - Aggregate(ref kind, ref places) => { - fn fmt_tuple(fmt: &mut Formatter<'_>, places: &[Operand<'_>]) -> fmt::Result { - let mut tuple_fmt = fmt.debug_tuple(""); - for place in places { - tuple_fmt.field(place); - } - tuple_fmt.finish() - } - - match **kind { - AggregateKind::Array(_) => write!(fmt, "{:?}", places), - - AggregateKind::Tuple => match places.len() { - 0 => write!(fmt, "()"), - 1 => write!(fmt, "({:?},)", places[0]), - _ => fmt_tuple(fmt, places), - }, - - AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => { - let variant_def = &adt_def.variants[variant]; - - let f = &mut *fmt; - ty::tls::with(|tcx| { - let substs = tcx.lift(&substs).expect("could not lift for printing"); - FmtPrinter::new(tcx, f, Namespace::ValueNS) - .print_def_path(variant_def.def_id, substs)?; - Ok(()) - })?; - - match variant_def.ctor_kind { - CtorKind::Const => Ok(()), - CtorKind::Fn => fmt_tuple(fmt, places), - CtorKind::Fictive => { - let mut struct_fmt = fmt.debug_struct(""); - for (field, place) in variant_def.fields.iter().zip(places) { - struct_fmt.field(&field.ident.as_str(), place); - } - struct_fmt.finish() - } - } - } - - AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| { - if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { - let name = if tcx.sess.opts.debugging_opts.span_free_formats { - let substs = tcx.lift(&substs).unwrap(); - format!( - "[closure@{}]", - tcx.def_path_str_with_substs(def_id, substs), - ) - } else { - format!("[closure@{:?}]", tcx.hir().span(hir_id)) - }; - let mut struct_fmt = fmt.debug_struct(&name); - - if let Some(upvars) = tcx.upvars(def_id) { - for (&var_id, place) in upvars.keys().zip(places) { - let var_name = tcx.hir().name(var_id); - struct_fmt.field(&var_name.as_str(), place); - } - } - - struct_fmt.finish() - } else { - write!(fmt, "[closure]") - } - }), - - AggregateKind::Generator(def_id, _, _) => ty::tls::with(|tcx| { - if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { - let name = format!("[generator@{:?}]", tcx.hir().span(hir_id)); - let mut struct_fmt = fmt.debug_struct(&name); - - if let Some(upvars) = tcx.upvars(def_id) { - for (&var_id, place) in upvars.keys().zip(places) { - let var_name = tcx.hir().name(var_id); - struct_fmt.field(&var_name.as_str(), place); - } - } - - struct_fmt.finish() - } else { - write!(fmt, "[generator]") - } - }), - } - } - } - } -} - -/////////////////////////////////////////////////////////////////////////// -/// Constants -/// -/// Two constants are equal if they are the same constant. Note that -/// this does not necessarily mean that they are "==" in Rust -- in -/// particular one must be wary of `NaN`! - -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] -pub struct Constant<'tcx> { - pub span: Span, - - /// Optional user-given type: for something like - /// `collect::<Vec<_>>`, this would be present and would - /// indicate that `Vec<_>` was explicitly specified. - /// - /// Needed for NLL to impose user-given type constraints. - pub user_ty: Option<UserTypeAnnotationIndex>, - - pub literal: &'tcx ty::Const<'tcx>, -} - -impl Constant<'tcx> { - pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> { - match self.literal.val.try_to_scalar() { - Some(Scalar::Ptr(ptr)) => match tcx.alloc_map.lock().get(ptr.alloc_id) { - Some(GlobalAlloc::Static(def_id)) => Some(def_id), - Some(_) => None, - None => { - tcx.sess.delay_span_bug(DUMMY_SP, "MIR cannot contain dangling const pointers"); - None - } - }, - _ => None, - } - } -} - -/// A collection of projections into user types. -/// -/// They are projections because a binding can occur a part of a -/// parent pattern that has been ascribed a type. -/// -/// Its a collection because there can be multiple type ascriptions on -/// the path from the root of the pattern down to the binding itself. -/// -/// An example: -/// -/// ```rust -/// struct S<'a>((i32, &'a str), String); -/// let S((_, w): (i32, &'static str), _): S = ...; -/// // ------ ^^^^^^^^^^^^^^^^^^^ (1) -/// // --------------------------------- ^ (2) -/// ``` -/// -/// The highlights labelled `(1)` show the subpattern `(_, w)` being -/// ascribed the type `(i32, &'static str)`. -/// -/// The highlights labelled `(2)` show the whole pattern being -/// ascribed the type `S`. -/// -/// In this example, when we descend to `w`, we will have built up the -/// following two projected types: -/// -/// * base: `S`, projection: `(base.0).1` -/// * base: `(i32, &'static str)`, projection: `base.1` -/// -/// The first will lead to the constraint `w: &'1 str` (for some -/// inferred region `'1`). The second will lead to the constraint `w: -/// &'static str`. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct UserTypeProjections { - pub(crate) contents: Vec<(UserTypeProjection, Span)>, -} - -impl<'tcx> UserTypeProjections { - pub fn none() -> Self { - UserTypeProjections { contents: vec![] } - } - - pub fn from_projections(projs: impl Iterator<Item = (UserTypeProjection, Span)>) -> Self { - UserTypeProjections { contents: projs.collect() } - } - - pub fn projections_and_spans( - &self, - ) -> impl Iterator<Item = &(UserTypeProjection, Span)> + ExactSizeIterator { - self.contents.iter() - } - - pub fn projections(&self) -> impl Iterator<Item = &UserTypeProjection> + ExactSizeIterator { - self.contents.iter().map(|&(ref user_type, _span)| user_type) - } - - pub fn push_projection(mut self, user_ty: &UserTypeProjection, span: Span) -> Self { - self.contents.push((user_ty.clone(), span)); - self - } - - fn map_projections( - mut self, - mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection, - ) -> Self { - self.contents = self.contents.drain(..).map(|(proj, span)| (f(proj), span)).collect(); - self - } - - pub fn index(self) -> Self { - self.map_projections(|pat_ty_proj| pat_ty_proj.index()) - } - - pub fn subslice(self, from: u32, to: u32) -> Self { - self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to)) - } - - pub fn deref(self) -> Self { - self.map_projections(|pat_ty_proj| pat_ty_proj.deref()) - } - - pub fn leaf(self, field: Field) -> Self { - self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field)) - } - - pub fn variant(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx, field: Field) -> Self { - self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field)) - } -} - -/// Encodes the effect of a user-supplied type annotation on the -/// subcomponents of a pattern. The effect is determined by applying the -/// given list of proejctions to some underlying base type. Often, -/// the projection element list `projs` is empty, in which case this -/// directly encodes a type in `base`. But in the case of complex patterns with -/// subpatterns and bindings, we want to apply only a *part* of the type to a variable, -/// in which case the `projs` vector is used. -/// -/// Examples: -/// -/// * `let x: T = ...` -- here, the `projs` vector is empty. -/// -/// * `let (x, _): T = ...` -- here, the `projs` vector would contain -/// `field[0]` (aka `.0`), indicating that the type of `s` is -/// determined by finding the type of the `.0` field from `T`. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, PartialEq)] -pub struct UserTypeProjection { - pub base: UserTypeAnnotationIndex, - pub projs: Vec<ProjectionKind>, -} - -impl Copy for ProjectionKind {} - -impl UserTypeProjection { - pub(crate) fn index(mut self) -> Self { - self.projs.push(ProjectionElem::Index(())); - self - } - - pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self { - self.projs.push(ProjectionElem::Subslice { from, to, from_end: true }); - self - } - - pub(crate) fn deref(mut self) -> Self { - self.projs.push(ProjectionElem::Deref); - self - } - - pub(crate) fn leaf(mut self, field: Field) -> Self { - self.projs.push(ProjectionElem::Field(field, ())); - self - } - - pub(crate) fn variant( - mut self, - adt_def: &'tcx AdtDef, - variant_index: VariantIdx, - field: Field, - ) -> Self { - self.projs.push(ProjectionElem::Downcast( - Some(adt_def.variants[variant_index].ident.name), - variant_index, - )); - self.projs.push(ProjectionElem::Field(field, ())); - self - } -} - -CloneTypeFoldableAndLiftImpls! { ProjectionKind, } - -impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - use crate::mir::ProjectionElem::*; - - let base = self.base.fold_with(folder); - let projs: Vec<_> = self - .projs - .iter() - .map(|&elem| match elem { - Deref => Deref, - Field(f, ()) => Field(f, ()), - Index(()) => Index(()), - Downcast(symbol, variantidx) => Downcast(symbol, variantidx), - ConstantIndex { offset, min_length, from_end } => { - ConstantIndex { offset, min_length, from_end } - } - Subslice { from, to, from_end } => Subslice { from, to, from_end }, - }) - .collect(); - - UserTypeProjection { base, projs } - } - - fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool { - self.base.visit_with(visitor) - // Note: there's nothing in `self.proj` to visit. - } -} - -rustc_index::newtype_index! { - pub struct Promoted { - derive [HashStable] - DEBUG_FORMAT = "promoted[{}]" - } -} - -impl<'tcx> Debug for Constant<'tcx> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - write!(fmt, "{}", self) - } -} - -impl<'tcx> Display for Constant<'tcx> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - write!(fmt, "const ")?; - // FIXME make the default pretty printing of raw pointers more detailed. Here we output the - // debug representation of raw pointers, so that the raw pointers in the mir dump output are - // detailed and just not '{pointer}'. - if let ty::RawPtr(_) = self.literal.ty.kind { - write!(fmt, "{:?} : {}", self.literal.val, self.literal.ty) - } else { - write!(fmt, "{}", self.literal) - } - } -} - -impl<'tcx> graph::DirectedGraph for Body<'tcx> { - type Node = BasicBlock; -} - -impl<'tcx> graph::WithNumNodes for Body<'tcx> { - fn num_nodes(&self) -> usize { - self.basic_blocks.len() - } -} - -impl<'tcx> graph::WithStartNode for Body<'tcx> { - fn start_node(&self) -> Self::Node { - START_BLOCK - } -} - -impl<'tcx> graph::WithSuccessors for Body<'tcx> { - fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter { - self.basic_blocks[node].terminator().successors().cloned() - } -} - -impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> { - type Item = BasicBlock; - type Iter = iter::Cloned<Successors<'b>>; -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)] -pub struct Location { - /// The block that the location is within. - pub block: BasicBlock, - - /// The location is the position of the start of the statement; or, if - /// `statement_index` equals the number of statements, then the start of the - /// terminator. - pub statement_index: usize, -} - -impl fmt::Debug for Location { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{:?}[{}]", self.block, self.statement_index) - } -} - -impl Location { - pub const START: Location = Location { block: START_BLOCK, statement_index: 0 }; - - /// Returns the location immediately after this one within the enclosing block. - /// - /// Note that if this location represents a terminator, then the - /// resulting location would be out of bounds and invalid. - pub fn successor_within_block(&self) -> Location { - Location { block: self.block, statement_index: self.statement_index + 1 } - } - - /// Returns `true` if `other` is earlier in the control flow graph than `self`. - pub fn is_predecessor_of<'tcx>( - &self, - other: Location, - body: ReadOnlyBodyAndCache<'_, 'tcx>, - ) -> bool { - // If we are in the same block as the other location and are an earlier statement - // then we are a predecessor of `other`. - if self.block == other.block && self.statement_index < other.statement_index { - return true; - } - - // If we're in another block, then we want to check that block is a predecessor of `other`. - let mut queue: Vec<BasicBlock> = body.predecessors_for(other.block).to_vec(); - let mut visited = FxHashSet::default(); - - while let Some(block) = queue.pop() { - // If we haven't visited this block before, then make sure we visit it's predecessors. - if visited.insert(block) { - queue.extend(body.predecessors_for(block).iter().cloned()); - } else { - continue; - } - - // If we found the block that `self` is in, then we are a predecessor of `other` (since - // we found that block by looking at the predecessors of `other`). - if self.block == block { - return true; - } - } - - false - } - - pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) -> bool { - if self.block == other.block { - self.statement_index <= other.statement_index - } else { - dominators.is_dominated_by(other.block, self.block) - } - } -} - -/* - * `TypeFoldable` implementations for MIR types -*/ - -CloneTypeFoldableAndLiftImpls! { - BlockTailInfo, - MirPhase, - SourceInfo, - FakeReadCause, - RetagKind, - SourceScope, - SourceScopeData, - SourceScopeLocalData, - UserTypeAnnotationIndex, -} - -impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - use crate::mir::TerminatorKind::*; - - let kind = match self.kind { - Goto { target } => Goto { target }, - SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt { - discr: discr.fold_with(folder), - switch_ty: switch_ty.fold_with(folder), - values: values.clone(), - targets: targets.clone(), - }, - Drop { ref location, target, unwind } => { - Drop { location: location.fold_with(folder), target, unwind } - } - DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace { - location: location.fold_with(folder), - value: value.fold_with(folder), - target, - unwind, - }, - Yield { ref value, resume, ref resume_arg, drop } => Yield { - value: value.fold_with(folder), - resume, - resume_arg: resume_arg.fold_with(folder), - drop, - }, - Call { ref func, ref args, ref destination, cleanup, from_hir_call } => { - let dest = - destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest)); - - Call { - func: func.fold_with(folder), - args: args.fold_with(folder), - destination: dest, - cleanup, - from_hir_call, - } - } - Assert { ref cond, expected, ref msg, target, cleanup } => { - use AssertKind::*; - let msg = match msg { - BoundsCheck { ref len, ref index } => { - BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) } - } - Overflow(_) - | OverflowNeg - | DivisionByZero - | RemainderByZero - | ResumedAfterReturn(_) - | ResumedAfterPanic(_) => msg.clone(), - }; - Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup } - } - GeneratorDrop => GeneratorDrop, - Resume => Resume, - Abort => Abort, - Return => Return, - Unreachable => Unreachable, - FalseEdges { real_target, imaginary_target } => { - FalseEdges { real_target, imaginary_target } - } - FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind }, - }; - Terminator { source_info: self.source_info, kind } - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - use crate::mir::TerminatorKind::*; - - match self.kind { - SwitchInt { ref discr, switch_ty, .. } => { - discr.visit_with(visitor) || switch_ty.visit_with(visitor) - } - Drop { ref location, .. } => location.visit_with(visitor), - DropAndReplace { ref location, ref value, .. } => { - location.visit_with(visitor) || value.visit_with(visitor) - } - Yield { ref value, .. } => value.visit_with(visitor), - Call { ref func, ref args, ref destination, .. } => { - let dest = if let Some((ref loc, _)) = *destination { - loc.visit_with(visitor) - } else { - false - }; - dest || func.visit_with(visitor) || args.visit_with(visitor) - } - Assert { ref cond, ref msg, .. } => { - if cond.visit_with(visitor) { - use AssertKind::*; - match msg { - BoundsCheck { ref len, ref index } => { - len.visit_with(visitor) || index.visit_with(visitor) - } - Overflow(_) - | OverflowNeg - | DivisionByZero - | RemainderByZero - | ResumedAfterReturn(_) - | ResumedAfterPanic(_) => false, - } - } else { - false - } - } - Goto { .. } - | Resume - | Abort - | Return - | GeneratorDrop - | Unreachable - | FalseEdges { .. } - | FalseUnwind { .. } => false, - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for GeneratorKind { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { - *self - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { - false - } -} - -impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) } - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.local.visit_with(visitor) || self.projection.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>(); - folder.tcx().intern_place_elems(&v) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - use crate::mir::Rvalue::*; - match *self { - Use(ref op) => Use(op.fold_with(folder)), - Repeat(ref op, len) => Repeat(op.fold_with(folder), len), - Ref(region, bk, ref place) => { - Ref(region.fold_with(folder), bk, place.fold_with(folder)) - } - AddressOf(mutability, ref place) => AddressOf(mutability, place.fold_with(folder)), - Len(ref place) => Len(place.fold_with(folder)), - Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), - BinaryOp(op, ref rhs, ref lhs) => { - BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) - } - CheckedBinaryOp(op, ref rhs, ref lhs) => { - CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) - } - UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)), - Discriminant(ref place) => Discriminant(place.fold_with(folder)), - NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)), - Aggregate(ref kind, ref fields) => { - let kind = box match **kind { - AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), - AggregateKind::Tuple => AggregateKind::Tuple, - AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt( - def, - v, - substs.fold_with(folder), - user_ty.fold_with(folder), - n, - ), - AggregateKind::Closure(id, substs) => { - AggregateKind::Closure(id, substs.fold_with(folder)) - } - AggregateKind::Generator(id, substs, movablity) => { - AggregateKind::Generator(id, substs.fold_with(folder), movablity) - } - }; - Aggregate(kind, fields.fold_with(folder)) - } - } - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - use crate::mir::Rvalue::*; - match *self { - Use(ref op) => op.visit_with(visitor), - Repeat(ref op, _) => op.visit_with(visitor), - Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor), - AddressOf(_, ref place) => place.visit_with(visitor), - Len(ref place) => place.visit_with(visitor), - Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor), - BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => { - rhs.visit_with(visitor) || lhs.visit_with(visitor) - } - UnaryOp(_, ref val) => val.visit_with(visitor), - Discriminant(ref place) => place.visit_with(visitor), - NullaryOp(_, ty) => ty.visit_with(visitor), - Aggregate(ref kind, ref fields) => { - (match **kind { - AggregateKind::Array(ty) => ty.visit_with(visitor), - AggregateKind::Tuple => false, - AggregateKind::Adt(_, _, substs, user_ty, _) => { - substs.visit_with(visitor) || user_ty.visit_with(visitor) - } - AggregateKind::Closure(_, substs) => substs.visit_with(visitor), - AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor), - }) || fields.visit_with(visitor) - } - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - match *self { - Operand::Copy(ref place) => Operand::Copy(place.fold_with(folder)), - Operand::Move(ref place) => Operand::Move(place.fold_with(folder)), - Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)), - } - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - match *self { - Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), - Operand::Constant(ref c) => c.visit_with(visitor), - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - use crate::mir::ProjectionElem::*; - - match *self { - Deref => Deref, - Field(f, ty) => Field(f, ty.fold_with(folder)), - Index(v) => Index(v.fold_with(folder)), - Downcast(symbol, variantidx) => Downcast(symbol, variantidx), - ConstantIndex { offset, min_length, from_end } => { - ConstantIndex { offset, min_length, from_end } - } - Subslice { from, to, from_end } => Subslice { from, to, from_end }, - } - } - - fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool { - use crate::mir::ProjectionElem::*; - - match self { - Field(_, ty) => ty.visit_with(visitor), - Index(v) => v.visit_with(visitor), - _ => false, - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for Field { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { - *self - } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { - false - } -} - -impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { - *self - } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { - false - } -} - -impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { - self.clone() - } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { - false - } -} - -impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - Constant { - span: self.span, - user_ty: self.user_ty.fold_with(folder), - literal: self.literal.fold_with(folder), - } - } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.literal.visit_with(visitor) - } -} diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs deleted file mode 100644 index 9a3ddfb0e82..00000000000 --- a/src/librustc/mir/mono.rs +++ /dev/null @@ -1,494 +0,0 @@ -use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId}; -use crate::ich::{Fingerprint, NodeIdHashingMode, StableHashingContext}; -use crate::session::config::OptLevel; -use crate::ty::print::obsolete::DefPathBasedNames; -use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; -use rustc_attr::InlineAttr; -use rustc_data_structures::base_n; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc_hir::HirId; -use rustc_span::source_map::Span; -use rustc_span::symbol::Symbol; -use std::fmt; -use std::hash::Hash; - -/// Describes how a monomorphization will be instantiated in object files. -#[derive(PartialEq)] -pub enum InstantiationMode { - /// There will be exactly one instance of the given MonoItem. It will have - /// external linkage so that it can be linked to from other codegen units. - GloballyShared { - /// In some compilation scenarios we may decide to take functions that - /// are typically `LocalCopy` and instead move them to `GloballyShared` - /// to avoid codegenning them a bunch of times. In this situation, - /// however, our local copy may conflict with other crates also - /// inlining the same function. - /// - /// This flag indicates that this situation is occurring, and informs - /// symbol name calculation that some extra mangling is needed to - /// avoid conflicts. Note that this may eventually go away entirely if - /// ThinLTO enables us to *always* have a globally shared instance of a - /// function within one crate's compilation. - may_conflict: bool, - }, - - /// Each codegen unit containing a reference to the given MonoItem will - /// have its own private copy of the function (with internal linkage). - LocalCopy, -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] -pub enum MonoItem<'tcx> { - Fn(Instance<'tcx>), - Static(DefId), - GlobalAsm(HirId), -} - -impl<'tcx> MonoItem<'tcx> { - pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize { - match *self { - MonoItem::Fn(instance) => { - // Estimate the size of a function based on how many statements - // it contains. - tcx.instance_def_size_estimate(instance.def) - } - // Conservatively estimate the size of a static declaration - // or assembly to be 1. - MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1, - } - } - - pub fn is_generic_fn(&self) -> bool { - match *self { - MonoItem::Fn(ref instance) => instance.substs.non_erasable_generics().next().is_some(), - MonoItem::Static(..) | MonoItem::GlobalAsm(..) => false, - } - } - - pub fn symbol_name(&self, tcx: TyCtxt<'tcx>) -> SymbolName { - match *self { - MonoItem::Fn(instance) => tcx.symbol_name(instance), - MonoItem::Static(def_id) => tcx.symbol_name(Instance::mono(tcx, def_id)), - MonoItem::GlobalAsm(hir_id) => { - let def_id = tcx.hir().local_def_id(hir_id); - SymbolName { name: Symbol::intern(&format!("global_asm_{:?}", def_id)) } - } - } - } - - pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode { - let generate_cgu_internal_copies = tcx - .sess - .opts - .debugging_opts - .inline_in_all_cgus - .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) - && !tcx.sess.opts.cg.link_dead_code; - - match *self { - MonoItem::Fn(ref instance) => { - let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id); - // If this function isn't inlined or otherwise has explicit - // linkage, then we'll be creating a globally shared version. - if self.explicit_linkage(tcx).is_some() - || !instance.def.generates_cgu_internal_copy(tcx) - || Some(instance.def_id()) == entry_def_id - { - return InstantiationMode::GloballyShared { may_conflict: false }; - } - - // At this point we don't have explicit linkage and we're an - // inlined function. If we're inlining into all CGUs then we'll - // be creating a local copy per CGU - if generate_cgu_internal_copies { - return InstantiationMode::LocalCopy; - } - - // Finally, if this is `#[inline(always)]` we're sure to respect - // that with an inline copy per CGU, but otherwise we'll be - // creating one copy of this `#[inline]` function which may - // conflict with upstream crates as it could be an exported - // symbol. - match tcx.codegen_fn_attrs(instance.def_id()).inline { - InlineAttr::Always => InstantiationMode::LocalCopy, - _ => InstantiationMode::GloballyShared { may_conflict: true }, - } - } - MonoItem::Static(..) | MonoItem::GlobalAsm(..) => { - InstantiationMode::GloballyShared { may_conflict: false } - } - } - } - - pub fn explicit_linkage(&self, tcx: TyCtxt<'tcx>) -> Option<Linkage> { - let def_id = match *self { - MonoItem::Fn(ref instance) => instance.def_id(), - MonoItem::Static(def_id) => def_id, - MonoItem::GlobalAsm(..) => return None, - }; - - let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); - codegen_fn_attrs.linkage - } - - /// Returns `true` if this instance is instantiable - whether it has no unsatisfied - /// predicates. - /// - /// In order to codegen an item, all of its predicates must hold, because - /// otherwise the item does not make sense. Type-checking ensures that - /// the predicates of every item that is *used by* a valid item *do* - /// hold, so we can rely on that. - /// - /// However, we codegen collector roots (reachable items) and functions - /// in vtables when they are seen, even if they are not used, and so they - /// might not be instantiable. For example, a programmer can define this - /// public function: - /// - /// pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone { - /// <&mut () as Clone>::clone(&s); - /// } - /// - /// That function can't be codegened, because the method `<&mut () as Clone>::clone` - /// does not exist. Luckily for us, that function can't ever be used, - /// because that would require for `&'a mut (): Clone` to hold, so we - /// can just not emit any code, or even a linker reference for it. - /// - /// Similarly, if a vtable method has such a signature, and therefore can't - /// be used, we can just not emit it and have a placeholder (a null pointer, - /// which will never be accessed) in its place. - pub fn is_instantiable(&self, tcx: TyCtxt<'tcx>) -> bool { - debug!("is_instantiable({:?})", self); - let (def_id, substs) = match *self { - MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs), - MonoItem::Static(def_id) => (def_id, InternalSubsts::empty()), - // global asm never has predicates - MonoItem::GlobalAsm(..) => return true, - }; - - tcx.substitute_normalize_and_test_predicates((def_id, &substs)) - } - - pub fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String { - return match *self { - MonoItem::Fn(instance) => to_string_internal(tcx, "fn ", instance, debug), - MonoItem::Static(def_id) => { - let instance = Instance::new(def_id, tcx.intern_substs(&[])); - to_string_internal(tcx, "static ", instance, debug) - } - MonoItem::GlobalAsm(..) => "global_asm".to_string(), - }; - - fn to_string_internal<'tcx>( - tcx: TyCtxt<'tcx>, - prefix: &str, - instance: Instance<'tcx>, - debug: bool, - ) -> String { - let mut result = String::with_capacity(32); - result.push_str(prefix); - let printer = DefPathBasedNames::new(tcx, false, false); - printer.push_instance_as_string(instance, &mut result, debug); - result - } - } - - pub fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option<Span> { - match *self { - MonoItem::Fn(Instance { def, .. }) => tcx.hir().as_local_hir_id(def.def_id()), - MonoItem::Static(def_id) => tcx.hir().as_local_hir_id(def_id), - MonoItem::GlobalAsm(hir_id) => Some(hir_id), - } - .map(|hir_id| tcx.hir().span(hir_id)) - } -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - ::std::mem::discriminant(self).hash_stable(hcx, hasher); - - match *self { - MonoItem::Fn(ref instance) => { - instance.hash_stable(hcx, hasher); - } - MonoItem::Static(def_id) => { - def_id.hash_stable(hcx, hasher); - } - MonoItem::GlobalAsm(node_id) => { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - node_id.hash_stable(hcx, hasher); - }) - } - } - } -} - -pub struct CodegenUnit<'tcx> { - /// A name for this CGU. Incremental compilation requires that - /// name be unique amongst **all** crates. Therefore, it should - /// contain something unique to this crate (e.g., a module path) - /// as well as the crate name and disambiguator. - name: Symbol, - items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>, - size_estimate: Option<usize>, -} - -#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub enum Linkage { - External, - AvailableExternally, - LinkOnceAny, - LinkOnceODR, - WeakAny, - WeakODR, - Appending, - Internal, - Private, - ExternalWeak, - Common, -} - -#[derive(Copy, Clone, PartialEq, Debug, HashStable)] -pub enum Visibility { - Default, - Hidden, - Protected, -} - -impl<'tcx> CodegenUnit<'tcx> { - pub fn new(name: Symbol) -> CodegenUnit<'tcx> { - CodegenUnit { name: name, items: Default::default(), size_estimate: None } - } - - pub fn name(&self) -> Symbol { - self.name - } - - pub fn set_name(&mut self, name: Symbol) { - self.name = name; - } - - pub fn items(&self) -> &FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)> { - &self.items - } - - pub fn items_mut(&mut self) -> &mut FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)> { - &mut self.items - } - - pub fn mangle_name(human_readable_name: &str) -> String { - // We generate a 80 bit hash from the name. This should be enough to - // avoid collisions and is still reasonably short for filenames. - let mut hasher = StableHasher::new(); - human_readable_name.hash(&mut hasher); - let hash: u128 = hasher.finish(); - let hash = hash & ((1u128 << 80) - 1); - base_n::encode(hash, base_n::CASE_INSENSITIVE) - } - - pub fn estimate_size(&mut self, tcx: TyCtxt<'tcx>) { - // Estimate the size of a codegen unit as (approximately) the number of MIR - // statements it corresponds to. - self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum()); - } - - pub fn size_estimate(&self) -> usize { - // Should only be called if `estimate_size` has previously been called. - self.size_estimate.expect("estimate_size must be called before getting a size_estimate") - } - - pub fn modify_size_estimate(&mut self, delta: usize) { - assert!(self.size_estimate.is_some()); - if let Some(size_estimate) = self.size_estimate { - self.size_estimate = Some(size_estimate + delta); - } - } - - pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool { - self.items().contains_key(item) - } - - pub fn work_product_id(&self) -> WorkProductId { - WorkProductId::from_cgu_name(&self.name().as_str()) - } - - pub fn work_product(&self, tcx: TyCtxt<'_>) -> WorkProduct { - let work_product_id = self.work_product_id(); - tcx.dep_graph - .previous_work_product(&work_product_id) - .unwrap_or_else(|| panic!("Could not find work-product for CGU `{}`", self.name())) - } - - pub fn items_in_deterministic_order( - &self, - tcx: TyCtxt<'tcx>, - ) -> Vec<(MonoItem<'tcx>, (Linkage, Visibility))> { - // The codegen tests rely on items being process in the same order as - // they appear in the file, so for local items, we sort by node_id first - #[derive(PartialEq, Eq, PartialOrd, Ord)] - pub struct ItemSortKey(Option<HirId>, SymbolName); - - fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey { - ItemSortKey( - match item { - MonoItem::Fn(ref instance) => { - match instance.def { - // We only want to take HirIds of user-defined - // instances into account. The others don't matter for - // the codegen tests and can even make item order - // unstable. - InstanceDef::Item(def_id) => tcx.hir().as_local_hir_id(def_id), - InstanceDef::VtableShim(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::Intrinsic(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) => None, - } - } - MonoItem::Static(def_id) => tcx.hir().as_local_hir_id(def_id), - MonoItem::GlobalAsm(hir_id) => Some(hir_id), - }, - item.symbol_name(tcx), - ) - } - - let mut items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect(); - items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i)); - items - } - - pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode { - DepConstructor::CompileCodegenUnit(tcx, self.name()) - } -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let CodegenUnit { - ref items, - name, - // The size estimate is not relevant to the hash - size_estimate: _, - } = *self; - - name.hash_stable(hcx, hasher); - - let mut items: Vec<(Fingerprint, _)> = items - .iter() - .map(|(mono_item, &attrs)| { - let mut hasher = StableHasher::new(); - mono_item.hash_stable(hcx, &mut hasher); - let mono_item_fingerprint = hasher.finish(); - (mono_item_fingerprint, attrs) - }) - .collect(); - - items.sort_unstable_by_key(|i| i.0); - items.hash_stable(hcx, hasher); - } -} - -pub struct CodegenUnitNameBuilder<'tcx> { - tcx: TyCtxt<'tcx>, - cache: FxHashMap<CrateNum, String>, -} - -impl CodegenUnitNameBuilder<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> Self { - CodegenUnitNameBuilder { tcx, cache: Default::default() } - } - - /// CGU names should fulfill the following requirements: - /// - They should be able to act as a file name on any kind of file system - /// - They should not collide with other CGU names, even for different versions - /// of the same crate. - /// - /// Consequently, we don't use special characters except for '.' and '-' and we - /// prefix each name with the crate-name and crate-disambiguator. - /// - /// This function will build CGU names of the form: - /// - /// ``` - /// <crate-name>.<crate-disambiguator>[-in-<local-crate-id>](-<component>)*[.<special-suffix>] - /// <local-crate-id> = <local-crate-name>.<local-crate-disambiguator> - /// ``` - /// - /// The '.' before `<special-suffix>` makes sure that names with a special - /// suffix can never collide with a name built out of regular Rust - /// identifiers (e.g., module paths). - pub fn build_cgu_name<I, C, S>( - &mut self, - cnum: CrateNum, - components: I, - special_suffix: Option<S>, - ) -> Symbol - where - I: IntoIterator<Item = C>, - C: fmt::Display, - S: fmt::Display, - { - let cgu_name = self.build_cgu_name_no_mangle(cnum, components, special_suffix); - - if self.tcx.sess.opts.debugging_opts.human_readable_cgu_names { - cgu_name - } else { - let cgu_name = &cgu_name.as_str(); - Symbol::intern(&CodegenUnit::mangle_name(cgu_name)) - } - } - - /// Same as `CodegenUnit::build_cgu_name()` but will never mangle the - /// resulting name. - pub fn build_cgu_name_no_mangle<I, C, S>( - &mut self, - cnum: CrateNum, - components: I, - special_suffix: Option<S>, - ) -> Symbol - where - I: IntoIterator<Item = C>, - C: fmt::Display, - S: fmt::Display, - { - use std::fmt::Write; - - let mut cgu_name = String::with_capacity(64); - - // Start out with the crate name and disambiguator - let tcx = self.tcx; - let crate_prefix = self.cache.entry(cnum).or_insert_with(|| { - // Whenever the cnum is not LOCAL_CRATE we also mix in the - // local crate's ID. Otherwise there can be collisions between CGUs - // instantiating stuff for upstream crates. - let local_crate_id = if cnum != LOCAL_CRATE { - let local_crate_disambiguator = format!("{}", tcx.crate_disambiguator(LOCAL_CRATE)); - format!("-in-{}.{}", tcx.crate_name(LOCAL_CRATE), &local_crate_disambiguator[0..8]) - } else { - String::new() - }; - - let crate_disambiguator = tcx.crate_disambiguator(cnum).to_string(); - // Using a shortened disambiguator of about 40 bits - format!("{}.{}{}", tcx.crate_name(cnum), &crate_disambiguator[0..8], local_crate_id) - }); - - write!(cgu_name, "{}", crate_prefix).unwrap(); - - // Add the components - for component in components { - write!(cgu_name, "-{}", component).unwrap(); - } - - if let Some(special_suffix) = special_suffix { - // We add a dot in here so it cannot clash with anything in a regular - // Rust identifier - write!(cgu_name, ".{}", special_suffix).unwrap(); - } - - Symbol::intern(&cgu_name[..]) - } -} diff --git a/src/librustc/mir/query.rs b/src/librustc/mir/query.rs deleted file mode 100644 index 824cdfe55bf..00000000000 --- a/src/librustc/mir/query.rs +++ /dev/null @@ -1,229 +0,0 @@ -//! Values computed by queries that use MIR. - -use crate::ty::{self, Ty}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::Lrc; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_index::bit_set::BitMatrix; -use rustc_index::vec::IndexVec; -use rustc_span::{Span, Symbol}; -use rustc_target::abi::VariantIdx; -use smallvec::SmallVec; - -use super::{Field, SourceInfo}; - -#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] -pub enum UnsafetyViolationKind { - General, - /// Permitted both in `const fn`s and regular `fn`s. - GeneralAndConstFn, - BorrowPacked(hir::HirId), -} - -#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] -pub struct UnsafetyViolation { - pub source_info: SourceInfo, - pub description: Symbol, - pub details: Symbol, - pub kind: UnsafetyViolationKind, -} - -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] -pub struct UnsafetyCheckResult { - /// Violations that are propagated *upwards* from this function. - pub violations: Lrc<[UnsafetyViolation]>, - /// `unsafe` blocks in this function, along with whether they are used. This is - /// used for the "unused_unsafe" lint. - pub unsafe_blocks: Lrc<[(hir::HirId, bool)]>, -} - -rustc_index::newtype_index! { - pub struct GeneratorSavedLocal { - derive [HashStable] - DEBUG_FORMAT = "_{}", - } -} - -/// The layout of generator state. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct GeneratorLayout<'tcx> { - /// The type of every local stored inside the generator. - pub field_tys: IndexVec<GeneratorSavedLocal, Ty<'tcx>>, - - /// Which of the above fields are in each variant. Note that one field may - /// be stored in multiple variants. - pub variant_fields: IndexVec<VariantIdx, IndexVec<Field, GeneratorSavedLocal>>, - - /// Which saved locals are storage-live at the same time. Locals that do not - /// have conflicts with each other are allowed to overlap in the computed - /// layout. - pub storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>, -} - -#[derive(Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct BorrowCheckResult<'tcx> { - /// All the opaque types that are restricted to concrete types - /// by this function. Unlike the value in `TypeckTables`, this has - /// unerased regions. - pub concrete_opaque_types: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>, - pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>, - pub used_mut_upvars: SmallVec<[Field; 8]>, -} - -/// The result of the `mir_const_qualif` query. -/// -/// Each field corresponds to an implementer of the `Qualif` trait in -/// `librustc_mir/transform/check_consts/qualifs.rs`. See that file for more information on each -/// `Qualif`. -#[derive(Clone, Copy, Debug, Default, RustcEncodable, RustcDecodable, HashStable)] -pub struct ConstQualifs { - pub has_mut_interior: bool, - pub needs_drop: bool, -} - -/// After we borrow check a closure, we are left with various -/// requirements that we have inferred between the free regions that -/// appear in the closure's signature or on its field types. These -/// requirements are then verified and proved by the closure's -/// creating function. This struct encodes those requirements. -/// -/// The requirements are listed as being between various -/// `RegionVid`. The 0th region refers to `'static`; subsequent region -/// vids refer to the free regions that appear in the closure (or -/// generator's) type, in order of appearance. (This numbering is -/// actually defined by the `UniversalRegions` struct in the NLL -/// region checker. See for example -/// `UniversalRegions::closure_mapping`.) Note that we treat the free -/// regions in the closure's type "as if" they were erased, so their -/// precise identity is not important, only their position. -/// -/// Example: If type check produces a closure with the closure substs: -/// -/// ```text -/// ClosureSubsts = [ -/// i8, // the "closure kind" -/// for<'x> fn(&'a &'x u32) -> &'x u32, // the "closure signature" -/// &'a String, // some upvar -/// ] -/// ``` -/// -/// here, there is one unique free region (`'a`) but it appears -/// twice. We would "renumber" each occurrence to a unique vid, as follows: -/// -/// ```text -/// ClosureSubsts = [ -/// i8, // the "closure kind" -/// for<'x> fn(&'1 &'x u32) -> &'x u32, // the "closure signature" -/// &'2 String, // some upvar -/// ] -/// ``` -/// -/// Now the code might impose a requirement like `'1: '2`. When an -/// instance of the closure is created, the corresponding free regions -/// can be extracted from its type and constrained to have the given -/// outlives relationship. -/// -/// In some cases, we have to record outlives requirements between -/// types and regions as well. In that case, if those types include -/// any regions, those regions are recorded as `ReClosureBound` -/// instances assigned one of these same indices. Those regions will -/// be substituted away by the creator. We use `ReClosureBound` in -/// that case because the regions must be allocated in the global -/// `TyCtxt`, and hence we cannot use `ReVar` (which is what we use -/// internally within the rest of the NLL code). -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct ClosureRegionRequirements<'tcx> { - /// The number of external regions defined on the closure. In our - /// example above, it would be 3 -- one for `'static`, then `'1` - /// and `'2`. This is just used for a sanity check later on, to - /// make sure that the number of regions we see at the callsite - /// matches. - pub num_external_vids: usize, - - /// Requirements between the various free regions defined in - /// indices. - pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>, -} - -/// Indicates an outlives-constraint between a type or between two -/// free regions declared on the closure. -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct ClosureOutlivesRequirement<'tcx> { - // This region or type ... - pub subject: ClosureOutlivesSubject<'tcx>, - - // ... must outlive this one. - pub outlived_free_region: ty::RegionVid, - - // If not, report an error here ... - pub blame_span: Span, - - // ... due to this reason. - pub category: ConstraintCategory, -} - -/// Outlives-constraints can be categorized to determine whether and why they -/// are interesting (for error reporting). Order of variants indicates sort -/// order of the category, thereby influencing diagnostic output. -/// -/// See also [rustc_mir::borrow_check::nll::constraints]. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[derive(RustcEncodable, RustcDecodable, HashStable)] -pub enum ConstraintCategory { - Return, - Yield, - UseAsConst, - UseAsStatic, - TypeAnnotation, - Cast, - - /// A constraint that came from checking the body of a closure. - /// - /// We try to get the category that the closure used when reporting this. - ClosureBounds, - CallArgument, - CopyBound, - SizedBound, - Assignment, - OpaqueType, - - /// A "boring" constraint (caused by the given location) is one that - /// the user probably doesn't want to see described in diagnostics, - /// because it is kind of an artifact of the type system setup. - /// Example: `x = Foo { field: y }` technically creates - /// intermediate regions representing the "type of `Foo { field: y - /// }`", and data flows from `y` into those variables, but they - /// are not very interesting. The assignment into `x` on the other - /// hand might be. - Boring, - // Boring and applicable everywhere. - BoringNoLocation, - - /// A constraint that doesn't correspond to anything the user sees. - Internal, -} - -/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing -/// that must outlive some region. -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub enum ClosureOutlivesSubject<'tcx> { - /// Subject is a type, typically a type parameter, but could also - /// be a projection. Indicates a requirement like `T: 'a` being - /// passed to the caller, where the type here is `T`. - /// - /// The type here is guaranteed not to contain any free regions at - /// present. - Ty(Ty<'tcx>), - - /// Subject is a free region from the closure. Indicates a requirement - /// like `'a: 'b` being passed to the caller; the region here is `'a`. - Region(ty::RegionVid), -} - -/// The constituent parts of an ADT or array. -#[derive(Copy, Clone, Debug, HashStable)] -pub struct DestructuredConst<'tcx> { - pub variant: VariantIdx, - pub fields: &'tcx [&'tcx ty::Const<'tcx>], -} diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs deleted file mode 100644 index e6c7c84494c..00000000000 --- a/src/librustc/mir/tcx.rs +++ /dev/null @@ -1,291 +0,0 @@ -/*! - * Methods for the various MIR types. These are intended for use after - * building is complete. - */ - -use crate::mir::*; -use crate::ty::layout::VariantIdx; -use crate::ty::subst::Subst; -use crate::ty::util::IntTypeExt; -use crate::ty::{self, Ty, TyCtxt}; -use rustc_hir as hir; - -#[derive(Copy, Clone, Debug, TypeFoldable)] -pub struct PlaceTy<'tcx> { - pub ty: Ty<'tcx>, - /// Downcast to a particular variant of an enum, if included. - pub variant_index: Option<VariantIdx>, -} - -// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers. -#[cfg(target_arch = "x86_64")] -static_assert_size!(PlaceTy<'_>, 16); - -impl<'tcx> PlaceTy<'tcx> { - pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> { - PlaceTy { ty, variant_index: None } - } - - /// `place_ty.field_ty(tcx, f)` computes the type at a given field - /// of a record or enum-variant. (Most clients of `PlaceTy` can - /// instead just extract the relevant type directly from their - /// `PlaceElem`, but some instances of `ProjectionElem<V, T>` do - /// not carry a `Ty` for `T`.) - /// - /// Note that the resulting type has not been normalized. - pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> { - let answer = match self.ty.kind { - ty::Adt(adt_def, substs) => { - let variant_def = match self.variant_index { - None => adt_def.non_enum_variant(), - Some(variant_index) => { - assert!(adt_def.is_enum()); - &adt_def.variants[variant_index] - } - }; - let field_def = &variant_def.fields[f.index()]; - field_def.ty(tcx, substs) - } - ty::Tuple(ref tys) => tys[f.index()].expect_ty(), - _ => bug!("extracting field of non-tuple non-adt: {:?}", self), - }; - debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer); - answer - } - - /// Convenience wrapper around `projection_ty_core` for - /// `PlaceElem`, where we can just use the `Ty` that is already - /// stored inline on field projection elems. - pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: &PlaceElem<'tcx>) -> PlaceTy<'tcx> { - self.projection_ty_core(tcx, ty::ParamEnv::empty(), elem, |_, _, ty| ty) - } - - /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` - /// projects `place_ty` onto `elem`, returning the appropriate - /// `Ty` or downcast variant corresponding to that projection. - /// The `handle_field` callback must map a `Field` to its `Ty`, - /// (which should be trivial when `T` = `Ty`). - pub fn projection_ty_core<V, T>( - self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - elem: &ProjectionElem<V, T>, - mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>, - ) -> PlaceTy<'tcx> - where - V: ::std::fmt::Debug, - T: ::std::fmt::Debug, - { - let answer = match *elem { - ProjectionElem::Deref => { - let ty = self - .ty - .builtin_deref(true) - .unwrap_or_else(|| { - bug!("deref projection of non-dereferenceable ty {:?}", self) - }) - .ty; - PlaceTy::from_ty(ty) - } - ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { - PlaceTy::from_ty(self.ty.builtin_index().unwrap()) - } - ProjectionElem::Subslice { from, to, from_end } => { - PlaceTy::from_ty(match self.ty.kind { - ty::Slice(..) => self.ty, - ty::Array(inner, _) if !from_end => tcx.mk_array(inner, (to - from) as u64), - ty::Array(inner, size) if from_end => { - let size = size.eval_usize(tcx, param_env); - let len = size - (from as u64) - (to as u64); - tcx.mk_array(inner, len) - } - _ => bug!("cannot subslice non-array type: `{:?}`", self), - }) - } - ProjectionElem::Downcast(_name, index) => { - PlaceTy { ty: self.ty, variant_index: Some(index) } - } - ProjectionElem::Field(ref f, ref fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), - }; - debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); - answer - } -} - -impl<'tcx> Place<'tcx> { - pub fn ty_from<D>( - local: Local, - projection: &[PlaceElem<'tcx>], - local_decls: &D, - tcx: TyCtxt<'tcx>, - ) -> PlaceTy<'tcx> - where - D: HasLocalDecls<'tcx>, - { - projection - .iter() - .fold(PlaceTy::from_ty(local_decls.local_decls()[local].ty), |place_ty, elem| { - place_ty.projection_ty(tcx, elem) - }) - } - - pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> - where - D: HasLocalDecls<'tcx>, - { - Place::ty_from(self.local, &self.projection, local_decls, tcx) - } -} - -pub enum RvalueInitializationState { - Shallow, - Deep, -} - -impl<'tcx> Rvalue<'tcx> { - pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> - where - D: HasLocalDecls<'tcx>, - { - match *self { - Rvalue::Use(ref operand) => operand.ty(local_decls, tcx), - Rvalue::Repeat(ref operand, count) => tcx.mk_array(operand.ty(local_decls, tcx), count), - Rvalue::Ref(reg, bk, ref place) => { - let place_ty = place.ty(local_decls, tcx).ty; - tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() }) - } - Rvalue::AddressOf(mutability, ref place) => { - let place_ty = place.ty(local_decls, tcx).ty; - tcx.mk_ptr(ty::TypeAndMut { ty: place_ty, mutbl: mutability.into() }) - } - Rvalue::Len(..) => tcx.types.usize, - Rvalue::Cast(.., ty) => ty, - Rvalue::BinaryOp(op, ref lhs, ref rhs) => { - let lhs_ty = lhs.ty(local_decls, tcx); - let rhs_ty = rhs.ty(local_decls, tcx); - op.ty(tcx, lhs_ty, rhs_ty) - } - Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => { - let lhs_ty = lhs.ty(local_decls, tcx); - let rhs_ty = rhs.ty(local_decls, tcx); - let ty = op.ty(tcx, lhs_ty, rhs_ty); - tcx.intern_tup(&[ty, tcx.types.bool]) - } - Rvalue::UnaryOp(UnOp::Not, ref operand) | Rvalue::UnaryOp(UnOp::Neg, ref operand) => { - operand.ty(local_decls, tcx) - } - Rvalue::Discriminant(ref place) => { - let ty = place.ty(local_decls, tcx).ty; - match ty.kind { - ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx), - ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx), - _ => { - // This can only be `0`, for now, so `u8` will suffice. - tcx.types.u8 - } - } - } - Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t), - Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize, - Rvalue::Aggregate(ref ak, ref ops) => match **ak { - AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64), - AggregateKind::Tuple => tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx))), - AggregateKind::Adt(def, _, substs, _, _) => tcx.type_of(def.did).subst(tcx, substs), - AggregateKind::Closure(did, substs) => tcx.mk_closure(did, substs), - AggregateKind::Generator(did, substs, movability) => { - tcx.mk_generator(did, substs, movability) - } - }, - } - } - - #[inline] - /// Returns `true` if this rvalue is deeply initialized (most rvalues) or - /// whether its only shallowly initialized (`Rvalue::Box`). - pub fn initialization_state(&self) -> RvalueInitializationState { - match *self { - Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow, - _ => RvalueInitializationState::Deep, - } - } -} - -impl<'tcx> Operand<'tcx> { - pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> - where - D: HasLocalDecls<'tcx>, - { - match self { - &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, - &Operand::Constant(ref c) => c.literal.ty, - } - } -} - -impl<'tcx> BinOp { - pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> { - // FIXME: handle SIMD correctly - match self { - &BinOp::Add - | &BinOp::Sub - | &BinOp::Mul - | &BinOp::Div - | &BinOp::Rem - | &BinOp::BitXor - | &BinOp::BitAnd - | &BinOp::BitOr => { - // these should be integers or floats of the same size. - assert_eq!(lhs_ty, rhs_ty); - lhs_ty - } - &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => { - lhs_ty // lhs_ty can be != rhs_ty - } - &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => { - tcx.types.bool - } - } - } -} - -impl BorrowKind { - pub fn to_mutbl_lossy(self) -> hir::Mutability { - match self { - BorrowKind::Mut { .. } => hir::Mutability::Mut, - BorrowKind::Shared => hir::Mutability::Not, - - // We have no type corresponding to a unique imm borrow, so - // use `&mut`. It gives all the capabilities of an `&uniq` - // and hence is a safe "over approximation". - BorrowKind::Unique => hir::Mutability::Mut, - - // We have no type corresponding to a shallow borrow, so use - // `&` as an approximation. - BorrowKind::Shallow => hir::Mutability::Not, - } - } -} - -impl BinOp { - pub fn to_hir_binop(self) -> hir::BinOpKind { - match self { - BinOp::Add => hir::BinOpKind::Add, - BinOp::Sub => hir::BinOpKind::Sub, - BinOp::Mul => hir::BinOpKind::Mul, - BinOp::Div => hir::BinOpKind::Div, - BinOp::Rem => hir::BinOpKind::Rem, - BinOp::BitXor => hir::BinOpKind::BitXor, - BinOp::BitAnd => hir::BinOpKind::BitAnd, - BinOp::BitOr => hir::BinOpKind::BitOr, - BinOp::Shl => hir::BinOpKind::Shl, - BinOp::Shr => hir::BinOpKind::Shr, - BinOp::Eq => hir::BinOpKind::Eq, - BinOp::Ne => hir::BinOpKind::Ne, - BinOp::Lt => hir::BinOpKind::Lt, - BinOp::Gt => hir::BinOpKind::Gt, - BinOp::Le => hir::BinOpKind::Le, - BinOp::Ge => hir::BinOpKind::Ge, - BinOp::Offset => unreachable!(), - } - } -} diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs deleted file mode 100644 index ed8129b1e09..00000000000 --- a/src/librustc/mir/traversal.rs +++ /dev/null @@ -1,294 +0,0 @@ -use rustc_index::bit_set::BitSet; - -use super::*; - -/// Preorder traversal of a graph. -/// -/// Preorder traversal is when each node is visited before any of its -/// successors -/// -/// ```text -/// -/// A -/// / \ -/// / \ -/// B C -/// \ / -/// \ / -/// D -/// ``` -/// -/// A preorder traversal of this graph is either `A B D C` or `A C D B` -#[derive(Clone)] -pub struct Preorder<'a, 'tcx> { - body: &'a Body<'tcx>, - visited: BitSet<BasicBlock>, - worklist: Vec<BasicBlock>, - root_is_start_block: bool, -} - -impl<'a, 'tcx> Preorder<'a, 'tcx> { - pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Preorder<'a, 'tcx> { - let worklist = vec![root]; - - Preorder { - body, - visited: BitSet::new_empty(body.basic_blocks().len()), - worklist, - root_is_start_block: root == START_BLOCK, - } - } -} - -pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Preorder<'a, 'tcx> { - Preorder::new(body, START_BLOCK) -} - -impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { - type Item = (BasicBlock, &'a BasicBlockData<'tcx>); - - fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { - while let Some(idx) = self.worklist.pop() { - if !self.visited.insert(idx) { - continue; - } - - let data = &self.body[idx]; - - if let Some(ref term) = data.terminator { - self.worklist.extend(term.successors()); - } - - return Some((idx, data)); - } - - None - } - - fn size_hint(&self) -> (usize, Option<usize>) { - // All the blocks, minus the number of blocks we've visited. - let upper = self.body.basic_blocks().len() - self.visited.count(); - - let lower = if self.root_is_start_block { - // We will visit all remaining blocks exactly once. - upper - } else { - self.worklist.len() - }; - - (lower, Some(upper)) - } -} - -/// Postorder traversal of a graph. -/// -/// Postorder traversal is when each node is visited after all of its -/// successors, except when the successor is only reachable by a back-edge -/// -/// -/// ```text -/// -/// A -/// / \ -/// / \ -/// B C -/// \ / -/// \ / -/// D -/// ``` -/// -/// A Postorder traversal of this graph is `D B C A` or `D C B A` -pub struct Postorder<'a, 'tcx> { - body: &'a Body<'tcx>, - visited: BitSet<BasicBlock>, - visit_stack: Vec<(BasicBlock, Successors<'a>)>, - root_is_start_block: bool, -} - -impl<'a, 'tcx> Postorder<'a, 'tcx> { - pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> { - let mut po = Postorder { - body, - visited: BitSet::new_empty(body.basic_blocks().len()), - visit_stack: Vec::new(), - root_is_start_block: root == START_BLOCK, - }; - - let data = &po.body[root]; - - if let Some(ref term) = data.terminator { - po.visited.insert(root); - po.visit_stack.push((root, term.successors())); - po.traverse_successor(); - } - - po - } - - fn traverse_successor(&mut self) { - // This is quite a complex loop due to 1. the borrow checker not liking it much - // and 2. what exactly is going on is not clear - // - // It does the actual traversal of the graph, while the `next` method on the iterator - // just pops off of the stack. `visit_stack` is a stack containing pairs of nodes and - // iterators over the successors of those nodes. Each iteration attempts to get the next - // node from the top of the stack, then pushes that node and an iterator over the - // successors to the top of the stack. This loop only grows `visit_stack`, stopping when - // we reach a child that has no children that we haven't already visited. - // - // For a graph that looks like this: - // - // A - // / \ - // / \ - // B C - // | | - // | | - // D | - // \ / - // \ / - // E - // - // The state of the stack starts out with just the root node (`A` in this case); - // [(A, [B, C])] - // - // When the first call to `traverse_successor` happens, the following happens: - // - // [(B, [D]), // `B` taken from the successors of `A`, pushed to the - // // top of the stack along with the successors of `B` - // (A, [C])] - // - // [(D, [E]), // `D` taken from successors of `B`, pushed to stack - // (B, []), - // (A, [C])] - // - // [(E, []), // `E` taken from successors of `D`, pushed to stack - // (D, []), - // (B, []), - // (A, [C])] - // - // Now that the top of the stack has no successors we can traverse, each item will - // be popped off during iteration until we get back to `A`. This yields [E, D, B]. - // - // When we yield `B` and call `traverse_successor`, we push `C` to the stack, but - // since we've already visited `E`, that child isn't added to the stack. The last - // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A] - loop { - let bb = if let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() { - if let Some(&bb) = iter.next() { - bb - } else { - break; - } - } else { - break; - }; - - if self.visited.insert(bb) { - if let Some(term) = &self.body[bb].terminator { - self.visit_stack.push((bb, term.successors())); - } - } - } - } -} - -pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> { - Postorder::new(body, START_BLOCK) -} - -impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { - type Item = (BasicBlock, &'a BasicBlockData<'tcx>); - - fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { - let next = self.visit_stack.pop(); - if next.is_some() { - self.traverse_successor(); - } - - next.map(|(bb, _)| (bb, &self.body[bb])) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - // All the blocks, minus the number of blocks we've visited. - let upper = self.body.basic_blocks().len() - self.visited.count(); - - let lower = if self.root_is_start_block { - // We will visit all remaining blocks exactly once. - upper - } else { - self.visit_stack.len() - }; - - (lower, Some(upper)) - } -} - -/// Reverse postorder traversal of a graph -/// -/// Reverse postorder is the reverse order of a postorder traversal. -/// This is different to a preorder traversal and represents a natural -/// linearization of control-flow. -/// -/// ```text -/// -/// A -/// / \ -/// / \ -/// B C -/// \ / -/// \ / -/// D -/// ``` -/// -/// A reverse postorder traversal of this graph is either `A B C D` or `A C B D` -/// Note that for a graph containing no loops (i.e., A DAG), this is equivalent to -/// a topological sort. -/// -/// Construction of a `ReversePostorder` traversal requires doing a full -/// postorder traversal of the graph, therefore this traversal should be -/// constructed as few times as possible. Use the `reset` method to be able -/// to re-use the traversal -#[derive(Clone)] -pub struct ReversePostorder<'a, 'tcx> { - body: &'a Body<'tcx>, - blocks: Vec<BasicBlock>, - idx: usize, -} - -impl<'a, 'tcx> ReversePostorder<'a, 'tcx> { - pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> ReversePostorder<'a, 'tcx> { - let blocks: Vec<_> = Postorder::new(body, root).map(|(bb, _)| bb).collect(); - - let len = blocks.len(); - - ReversePostorder { body, blocks, idx: len } - } - - pub fn reset(&mut self) { - self.idx = self.blocks.len(); - } -} - -pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorder<'a, 'tcx> { - ReversePostorder::new(body, START_BLOCK) -} - -impl<'a, 'tcx> Iterator for ReversePostorder<'a, 'tcx> { - type Item = (BasicBlock, &'a BasicBlockData<'tcx>); - - fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { - if self.idx == 0 { - return None; - } - self.idx -= 1; - - self.blocks.get(self.idx).map(|&bb| (bb, &self.body[bb])) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.idx, Some(self.idx)) - } -} - -impl<'a, 'tcx> ExactSizeIterator for ReversePostorder<'a, 'tcx> {} diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs deleted file mode 100644 index 409c981801b..00000000000 --- a/src/librustc/mir/visit.rs +++ /dev/null @@ -1,1177 +0,0 @@ -use crate::mir::*; -use crate::ty::subst::SubstsRef; -use crate::ty::{CanonicalUserTypeAnnotation, Ty}; -use rustc_span::Span; - -// # The MIR Visitor -// -// ## Overview -// -// There are two visitors, one for immutable and one for mutable references, -// but both are generated by the following macro. The code is written according -// to the following conventions: -// -// - introduce a `visit_foo` and a `super_foo` method for every MIR type -// - `visit_foo`, by default, calls `super_foo` -// - `super_foo`, by default, destructures the `foo` and calls `visit_foo` -// -// This allows you as a user to override `visit_foo` for types are -// interested in, and invoke (within that method) call -// `self.super_foo` to get the default behavior. Just as in an OO -// language, you should never call `super` methods ordinarily except -// in that circumstance. -// -// For the most part, we do not destructure things external to the -// MIR, e.g., types, spans, etc, but simply visit them and stop. This -// avoids duplication with other visitors like `TypeFoldable`. -// -// ## Updating -// -// The code is written in a very deliberate style intended to minimize -// the chance of things being overlooked. You'll notice that we always -// use pattern matching to reference fields and we ensure that all -// matches are exhaustive. -// -// For example, the `super_basic_block_data` method begins like this: -// -// ```rust -// fn super_basic_block_data(&mut self, -// block: BasicBlock, -// data: & $($mutability)? BasicBlockData<'tcx>) { -// let BasicBlockData { -// statements, -// terminator, -// is_cleanup: _ -// } = *data; -// -// for statement in statements { -// self.visit_statement(block, statement); -// } -// -// ... -// } -// ``` -// -// Here we used `let BasicBlockData { <fields> } = *data` deliberately, -// rather than writing `data.statements` in the body. This is because if one -// adds a new field to `BasicBlockData`, one will be forced to revise this code, -// and hence one will (hopefully) invoke the correct visit methods (if any). -// -// For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS. -// That means you never write `..` to skip over fields, nor do you write `_` -// to skip over variants in a `match`. -// -// The only place that `_` is acceptable is to match a field (or -// variant argument) that does not require visiting, as in -// `is_cleanup` above. - -macro_rules! body_cache_type { - (mut $a:lifetime, $tcx:lifetime) => { - &mut BodyAndCache<$tcx> - }; - ($a:lifetime, $tcx:lifetime) => { - ReadOnlyBodyAndCache<$a, $tcx> - }; -} - -macro_rules! make_mir_visitor { - ($visitor_trait_name:ident, $($mutability:ident)?) => { - pub trait $visitor_trait_name<'tcx> { - // Override these, and call `self.super_xxx` to revert back to the - // default behavior. - - fn visit_body( - &mut self, - body: body_cache_type!($($mutability)? '_, 'tcx) - ) { - self.super_body(body); - } - - fn visit_basic_block_data(&mut self, - block: BasicBlock, - data: & $($mutability)? BasicBlockData<'tcx>) { - self.super_basic_block_data(block, data); - } - - fn visit_source_scope_data(&mut self, - scope_data: & $($mutability)? SourceScopeData) { - self.super_source_scope_data(scope_data); - } - - fn visit_statement(&mut self, - statement: & $($mutability)? Statement<'tcx>, - location: Location) { - self.super_statement(statement, location); - } - - fn visit_assign(&mut self, - place: & $($mutability)? Place<'tcx>, - rvalue: & $($mutability)? Rvalue<'tcx>, - location: Location) { - self.super_assign(place, rvalue, location); - } - - fn visit_terminator(&mut self, - terminator: & $($mutability)? Terminator<'tcx>, - location: Location) { - self.super_terminator(terminator, location); - } - - fn visit_terminator_kind(&mut self, - kind: & $($mutability)? TerminatorKind<'tcx>, - location: Location) { - self.super_terminator_kind(kind, location); - } - - fn visit_assert_message(&mut self, - msg: & $($mutability)? AssertMessage<'tcx>, - location: Location) { - self.super_assert_message(msg, location); - } - - fn visit_rvalue(&mut self, - rvalue: & $($mutability)? Rvalue<'tcx>, - location: Location) { - self.super_rvalue(rvalue, location); - } - - fn visit_operand(&mut self, - operand: & $($mutability)? Operand<'tcx>, - location: Location) { - self.super_operand(operand, location); - } - - fn visit_ascribe_user_ty(&mut self, - place: & $($mutability)? Place<'tcx>, - variance: & $($mutability)? ty::Variance, - user_ty: & $($mutability)? UserTypeProjection, - location: Location) { - self.super_ascribe_user_ty(place, variance, user_ty, location); - } - - fn visit_retag(&mut self, - kind: & $($mutability)? RetagKind, - place: & $($mutability)? Place<'tcx>, - location: Location) { - self.super_retag(kind, place, location); - } - - fn visit_place(&mut self, - place: & $($mutability)? Place<'tcx>, - context: PlaceContext, - location: Location) { - self.super_place(place, context, location); - } - - fn visit_place_base(&mut self, - local: & $($mutability)? Local, - context: PlaceContext, - location: Location) { - self.super_place_base(local, context, location); - } - - visit_place_fns!($($mutability)?); - - fn visit_constant(&mut self, - constant: & $($mutability)? Constant<'tcx>, - location: Location) { - self.super_constant(constant, location); - } - - fn visit_span(&mut self, - span: & $($mutability)? Span) { - self.super_span(span); - } - - fn visit_source_info(&mut self, - source_info: & $($mutability)? SourceInfo) { - self.super_source_info(source_info); - } - - fn visit_ty(&mut self, - ty: $(& $mutability)? Ty<'tcx>, - _: TyContext) { - self.super_ty(ty); - } - - fn visit_user_type_projection( - &mut self, - ty: & $($mutability)? UserTypeProjection, - ) { - self.super_user_type_projection(ty); - } - - fn visit_user_type_annotation( - &mut self, - index: UserTypeAnnotationIndex, - ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>, - ) { - self.super_user_type_annotation(index, ty); - } - - fn visit_region(&mut self, - region: & $($mutability)? ty::Region<'tcx>, - _: Location) { - self.super_region(region); - } - - fn visit_const(&mut self, - constant: & $($mutability)? &'tcx ty::Const<'tcx>, - _: Location) { - self.super_const(constant); - } - - fn visit_substs(&mut self, - substs: & $($mutability)? SubstsRef<'tcx>, - _: Location) { - self.super_substs(substs); - } - - fn visit_local_decl(&mut self, - local: Local, - local_decl: & $($mutability)? LocalDecl<'tcx>) { - self.super_local_decl(local, local_decl); - } - - fn visit_var_debug_info(&mut self, - var_debug_info: & $($mutability)* VarDebugInfo<'tcx>) { - self.super_var_debug_info(var_debug_info); - } - - fn visit_local(&mut self, - _local: & $($mutability)? Local, - _context: PlaceContext, - _location: Location) { - } - - fn visit_source_scope(&mut self, - scope: & $($mutability)? SourceScope) { - self.super_source_scope(scope); - } - - // The `super_xxx` methods comprise the default behavior and are - // not meant to be overridden. - - fn super_body( - &mut self, - $($mutability)? body: body_cache_type!($($mutability)? '_, 'tcx) - ) { - let span = body.span; - if let Some(yield_ty) = &$($mutability)? body.yield_ty { - self.visit_ty(yield_ty, TyContext::YieldTy(SourceInfo { - span, - scope: OUTERMOST_SOURCE_SCOPE, - })); - } - - // for best performance, we want to use an iterator rather - // than a for-loop, to avoid calling `body::Body::invalidate` for - // each basic block. - macro_rules! basic_blocks { - (mut) => (body.basic_blocks_mut().iter_enumerated_mut()); - () => (body.basic_blocks().iter_enumerated()); - }; - for (bb, data) in basic_blocks!($($mutability)?) { - self.visit_basic_block_data(bb, data); - } - - let body: & $($mutability)? Body<'_> = & $($mutability)? body; - for scope in &$($mutability)? body.source_scopes { - self.visit_source_scope_data(scope); - } - - self.visit_ty(&$($mutability)? body.return_ty(), TyContext::ReturnTy(SourceInfo { - span: body.span, - scope: OUTERMOST_SOURCE_SCOPE, - })); - - for local in body.local_decls.indices() { - self.visit_local_decl(local, & $($mutability)? body.local_decls[local]); - } - - macro_rules! type_annotations { - (mut) => (body.user_type_annotations.iter_enumerated_mut()); - () => (body.user_type_annotations.iter_enumerated()); - }; - - for (index, annotation) in type_annotations!($($mutability)?) { - self.visit_user_type_annotation( - index, annotation - ); - } - - for var_debug_info in &$($mutability)? body.var_debug_info { - self.visit_var_debug_info(var_debug_info); - } - - self.visit_span(&$($mutability)? body.span); - } - - fn super_basic_block_data(&mut self, - block: BasicBlock, - data: & $($mutability)? BasicBlockData<'tcx>) { - let BasicBlockData { - statements, - terminator, - is_cleanup: _ - } = data; - - let mut index = 0; - for statement in statements { - let location = Location { block: block, statement_index: index }; - self.visit_statement(statement, location); - index += 1; - } - - if let Some(terminator) = terminator { - let location = Location { block: block, statement_index: index }; - self.visit_terminator(terminator, location); - } - } - - fn super_source_scope_data(&mut self, scope_data: & $($mutability)? SourceScopeData) { - let SourceScopeData { - span, - parent_scope, - local_data: _, - } = scope_data; - - self.visit_span(span); - if let Some(parent_scope) = parent_scope { - self.visit_source_scope(parent_scope); - } - } - - fn super_statement(&mut self, - statement: & $($mutability)? Statement<'tcx>, - location: Location) { - let Statement { - source_info, - kind, - } = statement; - - self.visit_source_info(source_info); - match kind { - StatementKind::Assign( - box(ref $($mutability)? place, ref $($mutability)? rvalue) - ) => { - self.visit_assign(place, rvalue, location); - } - StatementKind::FakeRead(_, place) => { - self.visit_place( - place, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), - location - ); - } - StatementKind::SetDiscriminant { place, .. } => { - self.visit_place( - place, - PlaceContext::MutatingUse(MutatingUseContext::Store), - location - ); - } - StatementKind::StorageLive(local) => { - self.visit_local( - local, - PlaceContext::NonUse(NonUseContext::StorageLive), - location - ); - } - StatementKind::StorageDead(local) => { - self.visit_local( - local, - PlaceContext::NonUse(NonUseContext::StorageDead), - location - ); - } - StatementKind::InlineAsm(asm) => { - for output in & $($mutability)? asm.outputs[..] { - self.visit_place( - output, - PlaceContext::MutatingUse(MutatingUseContext::AsmOutput), - location - ); - } - for (span, input) in & $($mutability)? asm.inputs[..] { - self.visit_span(span); - self.visit_operand(input, location); - } - } - StatementKind::Retag(kind, place) => { - self.visit_retag(kind, place, location); - } - StatementKind::AscribeUserType( - box(ref $($mutability)? place, ref $($mutability)? user_ty), - variance - ) => { - self.visit_ascribe_user_ty(place, variance, user_ty, location); - } - StatementKind::Nop => {} - } - } - - fn super_assign(&mut self, - place: &$($mutability)? Place<'tcx>, - rvalue: &$($mutability)? Rvalue<'tcx>, - location: Location) { - self.visit_place( - place, - PlaceContext::MutatingUse(MutatingUseContext::Store), - location - ); - self.visit_rvalue(rvalue, location); - } - - fn super_terminator(&mut self, - terminator: &$($mutability)? Terminator<'tcx>, - location: Location) { - let Terminator { source_info, kind } = terminator; - - self.visit_source_info(source_info); - self.visit_terminator_kind(kind, location); - } - - fn super_terminator_kind(&mut self, - kind: & $($mutability)? TerminatorKind<'tcx>, - source_location: Location) { - match kind { - TerminatorKind::Goto { .. } | - TerminatorKind::Resume | - TerminatorKind::Abort | - TerminatorKind::Return | - TerminatorKind::GeneratorDrop | - TerminatorKind::Unreachable | - TerminatorKind::FalseEdges { .. } | - TerminatorKind::FalseUnwind { .. } => { - } - - TerminatorKind::SwitchInt { - discr, - switch_ty, - values: _, - targets: _ - } => { - self.visit_operand(discr, source_location); - self.visit_ty(switch_ty, TyContext::Location(source_location)); - } - - TerminatorKind::Drop { - location, - target: _, - unwind: _, - } => { - self.visit_place( - location, - PlaceContext::MutatingUse(MutatingUseContext::Drop), - source_location - ); - } - - TerminatorKind::DropAndReplace { - location, - value, - target: _, - unwind: _, - } => { - self.visit_place( - location, - PlaceContext::MutatingUse(MutatingUseContext::Drop), - source_location - ); - self.visit_operand(value, source_location); - } - - TerminatorKind::Call { - func, - args, - destination, - cleanup: _, - from_hir_call: _, - } => { - self.visit_operand(func, source_location); - for arg in args { - self.visit_operand(arg, source_location); - } - if let Some((destination, _)) = destination { - self.visit_place( - destination, - PlaceContext::MutatingUse(MutatingUseContext::Call), - source_location - ); - } - } - - TerminatorKind::Assert { - cond, - expected: _, - msg, - target: _, - cleanup: _, - } => { - self.visit_operand(cond, source_location); - self.visit_assert_message(msg, source_location); - } - - TerminatorKind::Yield { - value, - resume: _, - resume_arg, - drop: _, - } => { - self.visit_operand(value, source_location); - self.visit_place( - resume_arg, - PlaceContext::MutatingUse(MutatingUseContext::Store), - source_location, - ); - } - - } - } - - fn super_assert_message(&mut self, - msg: & $($mutability)? AssertMessage<'tcx>, - location: Location) { - use crate::mir::AssertKind::*; - match msg { - BoundsCheck { len, index } => { - self.visit_operand(len, location); - self.visit_operand(index, location); - } - Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero | - ResumedAfterReturn(_) | ResumedAfterPanic(_) => { - // Nothing to visit - } - } - } - - fn super_rvalue(&mut self, - rvalue: & $($mutability)? Rvalue<'tcx>, - location: Location) { - match rvalue { - Rvalue::Use(operand) => { - self.visit_operand(operand, location); - } - - Rvalue::Repeat(value, _) => { - self.visit_operand(value, location); - } - - Rvalue::Ref(r, bk, path) => { - self.visit_region(r, location); - let ctx = match bk { - BorrowKind::Shared => PlaceContext::NonMutatingUse( - NonMutatingUseContext::SharedBorrow - ), - BorrowKind::Shallow => PlaceContext::NonMutatingUse( - NonMutatingUseContext::ShallowBorrow - ), - BorrowKind::Unique => PlaceContext::NonMutatingUse( - NonMutatingUseContext::UniqueBorrow - ), - BorrowKind::Mut { .. } => - PlaceContext::MutatingUse(MutatingUseContext::Borrow), - }; - self.visit_place(path, ctx, location); - } - - Rvalue::AddressOf(m, path) => { - let ctx = match m { - Mutability::Mut => PlaceContext::MutatingUse( - MutatingUseContext::AddressOf - ), - Mutability::Not => PlaceContext::NonMutatingUse( - NonMutatingUseContext::AddressOf - ), - }; - self.visit_place(path, ctx, location); - } - - Rvalue::Len(path) => { - self.visit_place( - path, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), - location - ); - } - - Rvalue::Cast(_cast_kind, operand, ty) => { - self.visit_operand(operand, location); - self.visit_ty(ty, TyContext::Location(location)); - } - - Rvalue::BinaryOp(_bin_op, lhs, rhs) - | Rvalue::CheckedBinaryOp(_bin_op, lhs, rhs) => { - self.visit_operand(lhs, location); - self.visit_operand(rhs, location); - } - - Rvalue::UnaryOp(_un_op, op) => { - self.visit_operand(op, location); - } - - Rvalue::Discriminant(place) => { - self.visit_place( - place, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), - location - ); - } - - Rvalue::NullaryOp(_op, ty) => { - self.visit_ty(ty, TyContext::Location(location)); - } - - Rvalue::Aggregate(kind, operands) => { - let kind = &$($mutability)? **kind; - match kind { - AggregateKind::Array(ty) => { - self.visit_ty(ty, TyContext::Location(location)); - } - AggregateKind::Tuple => { - } - AggregateKind::Adt( - _adt_def, - _variant_index, - substs, - _user_substs, - _active_field_index - ) => { - self.visit_substs(substs, location); - } - AggregateKind::Closure( - _, - closure_substs - ) => { - self.visit_substs(closure_substs, location); - } - AggregateKind::Generator( - _, - generator_substs, - _movability, - ) => { - self.visit_substs(generator_substs, location); - } - } - - for operand in operands { - self.visit_operand(operand, location); - } - } - } - } - - fn super_operand(&mut self, - operand: & $($mutability)? Operand<'tcx>, - location: Location) { - match operand { - Operand::Copy(place) => { - self.visit_place( - place, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), - location - ); - } - Operand::Move(place) => { - self.visit_place( - place, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Move), - location - ); - } - Operand::Constant(constant) => { - self.visit_constant(constant, location); - } - } - } - - fn super_ascribe_user_ty(&mut self, - place: & $($mutability)? Place<'tcx>, - _variance: & $($mutability)? ty::Variance, - user_ty: & $($mutability)? UserTypeProjection, - location: Location) { - self.visit_place( - place, - PlaceContext::NonUse(NonUseContext::AscribeUserTy), - location - ); - self.visit_user_type_projection(user_ty); - } - - fn super_retag(&mut self, - _kind: & $($mutability)? RetagKind, - place: & $($mutability)? Place<'tcx>, - location: Location) { - self.visit_place( - place, - PlaceContext::MutatingUse(MutatingUseContext::Retag), - location, - ); - } - - fn super_place_base(&mut self, - local: & $($mutability)? Local, - context: PlaceContext, - location: Location) { - self.visit_local(local, context, location); - } - - fn super_local_decl(&mut self, - local: Local, - local_decl: & $($mutability)? LocalDecl<'tcx>) { - let LocalDecl { - mutability: _, - ty, - user_ty, - source_info, - internal: _, - local_info: _, - is_block_tail: _, - } = local_decl; - - self.visit_ty(ty, TyContext::LocalDecl { - local, - source_info: *source_info, - }); - for (user_ty, _) in & $($mutability)? user_ty.contents { - self.visit_user_type_projection(user_ty); - } - self.visit_source_info(source_info); - } - - fn super_var_debug_info(&mut self, - var_debug_info: & $($mutability)? VarDebugInfo<'tcx>) { - let VarDebugInfo { - name: _, - source_info, - place, - } = var_debug_info; - - self.visit_source_info(source_info); - let location = START_BLOCK.start_location(); - self.visit_place( - place, - PlaceContext::NonUse(NonUseContext::VarDebugInfo), - location, - ); - } - - fn super_source_scope(&mut self, - _scope: & $($mutability)? SourceScope) { - } - - fn super_constant(&mut self, - constant: & $($mutability)? Constant<'tcx>, - location: Location) { - let Constant { - span, - user_ty, - literal, - } = constant; - - self.visit_span(span); - drop(user_ty); // no visit method for this - self.visit_const(literal, location); - } - - fn super_span(&mut self, _span: & $($mutability)? Span) { - } - - fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) { - let SourceInfo { - span, - scope, - } = source_info; - - self.visit_span(span); - self.visit_source_scope(scope); - } - - fn super_user_type_projection( - &mut self, - _ty: & $($mutability)? UserTypeProjection, - ) { - } - - fn super_user_type_annotation( - &mut self, - _index: UserTypeAnnotationIndex, - ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>, - ) { - self.visit_span(& $($mutability)? ty.span); - self.visit_ty(& $($mutability)? ty.inferred_ty, TyContext::UserTy(ty.span)); - } - - fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) { - } - - fn super_region(&mut self, _region: & $($mutability)? ty::Region<'tcx>) { - } - - fn super_const(&mut self, _const: & $($mutability)? &'tcx ty::Const<'tcx>) { - } - - fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) { - } - - // Convenience methods - - fn visit_location( - &mut self, - body: body_cache_type!($($mutability)? '_, 'tcx), - location: Location - ) { - let basic_block = & $($mutability)? body[location.block]; - if basic_block.statements.len() == location.statement_index { - if let Some(ref $($mutability)? terminator) = basic_block.terminator { - self.visit_terminator(terminator, location) - } - } else { - let statement = & $($mutability)? - basic_block.statements[location.statement_index]; - self.visit_statement(statement, location) - } - } - } - } -} - -macro_rules! visit_place_fns { - (mut) => ( - fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; - - fn super_place( - &mut self, - place: &mut Place<'tcx>, - context: PlaceContext, - location: Location, - ) { - self.visit_place_base(&mut place.local, context, location); - - if let Some(new_projection) = self.process_projection(&place.projection) { - place.projection = self.tcx().intern_place_elems(&new_projection); - } - } - - fn process_projection( - &mut self, - projection: &'a [PlaceElem<'tcx>], - ) -> Option<Vec<PlaceElem<'tcx>>> { - let mut projection = Cow::Borrowed(projection); - - for i in 0..projection.len() { - if let Some(elem) = projection.get(i) { - if let Some(elem) = self.process_projection_elem(elem) { - // This converts the borrowed projection into `Cow::Owned(_)` and returns a - // clone of the projection so we can mutate and reintern later. - let vec = projection.to_mut(); - vec[i] = elem; - } - } - } - - match projection { - Cow::Borrowed(_) => None, - Cow::Owned(vec) => Some(vec), - } - } - - fn process_projection_elem( - &mut self, - _elem: &PlaceElem<'tcx>, - ) -> Option<PlaceElem<'tcx>> { - None - } - ); - - () => ( - fn visit_projection( - &mut self, - local: &Local, - projection: &[PlaceElem<'tcx>], - context: PlaceContext, - location: Location, - ) { - self.super_projection(local, projection, context, location); - } - - fn visit_projection_elem( - &mut self, - local: &Local, - proj_base: &[PlaceElem<'tcx>], - elem: &PlaceElem<'tcx>, - context: PlaceContext, - location: Location, - ) { - self.super_projection_elem(local, proj_base, elem, context, location); - } - - fn super_place( - &mut self, - place: &Place<'tcx>, - context: PlaceContext, - location: Location, - ) { - let mut context = context; - - if !place.projection.is_empty() { - context = if context.is_mutating_use() { - PlaceContext::MutatingUse(MutatingUseContext::Projection) - } else { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) - }; - } - - self.visit_place_base(&place.local, context, location); - - self.visit_projection(&place.local, - &place.projection, - context, - location); - } - - fn super_projection( - &mut self, - local: &Local, - projection: &[PlaceElem<'tcx>], - context: PlaceContext, - location: Location, - ) { - let mut cursor = projection; - while let [proj_base @ .., elem] = cursor { - cursor = proj_base; - self.visit_projection_elem(local, cursor, elem, context, location); - } - } - - fn super_projection_elem( - &mut self, - _local: &Local, - _proj_base: &[PlaceElem<'tcx>], - elem: &PlaceElem<'tcx>, - _context: PlaceContext, - location: Location, - ) { - match elem { - ProjectionElem::Field(_field, ty) => { - self.visit_ty(ty, TyContext::Location(location)); - } - ProjectionElem::Index(local) => { - self.visit_local( - local, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), - location - ); - } - ProjectionElem::Deref | - ProjectionElem::Subslice { from: _, to: _, from_end: _ } | - ProjectionElem::ConstantIndex { offset: _, - min_length: _, - from_end: _ } | - ProjectionElem::Downcast(_, _) => { - } - } - } - ); -} - -make_mir_visitor!(Visitor,); -make_mir_visitor!(MutVisitor, mut); - -pub trait MirVisitable<'tcx> { - fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>); -} - -impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> { - fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { - visitor.visit_statement(self, location) - } -} - -impl<'tcx> MirVisitable<'tcx> for Terminator<'tcx> { - fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { - visitor.visit_terminator(self, location) - } -} - -impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> { - fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { - visitor.visit_terminator(self.as_ref().unwrap(), location) - } -} - -/// Extra information passed to `visit_ty` and friends to give context -/// about where the type etc appears. -#[derive(Debug)] -pub enum TyContext { - LocalDecl { - /// The index of the local variable we are visiting. - local: Local, - - /// The source location where this local variable was declared. - source_info: SourceInfo, - }, - - /// The inferred type of a user type annotation. - UserTy(Span), - - /// The return type of the function. - ReturnTy(SourceInfo), - - YieldTy(SourceInfo), - - /// A type found at some location. - Location(Location), -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum NonMutatingUseContext { - /// Being inspected in some way, like loading a len. - Inspect, - /// Consumed as part of an operand. - Copy, - /// Consumed as part of an operand. - Move, - /// Shared borrow. - SharedBorrow, - /// Shallow borrow. - ShallowBorrow, - /// Unique borrow. - UniqueBorrow, - /// AddressOf for *const pointer. - AddressOf, - /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place. - /// For example, the projection `x.y` is not marked as a mutation in these cases: - /// - /// z = x.y; - /// f(&x.y); - /// - Projection, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum MutatingUseContext { - /// Appears as LHS of an assignment. - Store, - /// Can often be treated as a `Store`, but needs to be separate because - /// ASM is allowed to read outputs as well, so a `Store`-`AsmOutput` sequence - /// cannot be simplified the way a `Store`-`Store` can be. - AsmOutput, - /// Destination of a call. - Call, - /// Being dropped. - Drop, - /// Mutable borrow. - Borrow, - /// AddressOf for *mut pointer. - AddressOf, - /// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place. - /// For example, the projection `x.y` is marked as a mutation in these cases: - /// - /// x.y = ...; - /// f(&mut x.y); - /// - Projection, - /// Retagging, a "Stacked Borrows" shadow state operation - Retag, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum NonUseContext { - /// Starting a storage live range. - StorageLive, - /// Ending a storage live range. - StorageDead, - /// User type annotation assertions for NLL. - AscribeUserTy, - /// The data of an user variable, for debug info. - VarDebugInfo, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum PlaceContext { - NonMutatingUse(NonMutatingUseContext), - MutatingUse(MutatingUseContext), - NonUse(NonUseContext), -} - -impl PlaceContext { - /// Returns `true` if this place context represents a drop. - pub fn is_drop(&self) -> bool { - match *self { - PlaceContext::MutatingUse(MutatingUseContext::Drop) => true, - _ => false, - } - } - - /// Returns `true` if this place context represents a borrow. - pub fn is_borrow(&self) -> bool { - match *self { - PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) - | PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) - | PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) - | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => true, - _ => false, - } - } - - /// Returns `true` if this place context represents a storage live or storage dead marker. - pub fn is_storage_marker(&self) -> bool { - match *self { - PlaceContext::NonUse(NonUseContext::StorageLive) - | PlaceContext::NonUse(NonUseContext::StorageDead) => true, - _ => false, - } - } - - /// Returns `true` if this place context represents a storage live marker. - pub fn is_storage_live_marker(&self) -> bool { - match *self { - PlaceContext::NonUse(NonUseContext::StorageLive) => true, - _ => false, - } - } - - /// Returns `true` if this place context represents a storage dead marker. - pub fn is_storage_dead_marker(&self) -> bool { - match *self { - PlaceContext::NonUse(NonUseContext::StorageDead) => true, - _ => false, - } - } - - /// Returns `true` if this place context represents a use that potentially changes the value. - pub fn is_mutating_use(&self) -> bool { - match *self { - PlaceContext::MutatingUse(..) => true, - _ => false, - } - } - - /// Returns `true` if this place context represents a use that does not change the value. - pub fn is_nonmutating_use(&self) -> bool { - match *self { - PlaceContext::NonMutatingUse(..) => true, - _ => false, - } - } - - /// Returns `true` if this place context represents a use. - pub fn is_use(&self) -> bool { - match *self { - PlaceContext::NonUse(..) => false, - _ => true, - } - } - - /// Returns `true` if this place context represents an assignment statement. - pub fn is_place_assignment(&self) -> bool { - match *self { - PlaceContext::MutatingUse(MutatingUseContext::Store) - | PlaceContext::MutatingUse(MutatingUseContext::Call) - | PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) => true, - _ => false, - } - } -} diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs deleted file mode 100644 index 3a6961660fd..00000000000 --- a/src/librustc/query/mod.rs +++ /dev/null @@ -1,1261 +0,0 @@ -use crate::dep_graph::{DepKind, DepNode, RecoverKey, SerializedDepNodeIndex}; -use crate::mir; -use crate::mir::interpret::{GlobalId, LitToConstInput}; -use crate::traits; -use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, -}; -use crate::ty::query::queries; -use crate::ty::query::QueryDescription; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex}; - -use rustc_span::symbol::Symbol; -use std::borrow::Cow; - -fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String { - if def_id.is_top_level_module() { - format!("top-level module") - } else { - format!("module `{}`", tcx.def_path_str(def_id)) - } -} - -// Each of these queries corresponds to a function pointer field in the -// `Providers` struct for requesting a value of that type, and a method -// on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way -// which memoizes and does dep-graph tracking, wrapping around the actual -// `Providers` that the driver creates (using several `rustc_*` crates). -// -// The result type of each query must implement `Clone`, and additionally -// `ty::query::values::Value`, which produces an appropriate placeholder -// (error) value if the query resulted in a query cycle. -// Queries marked with `fatal_cycle` do not need the latter implementation, -// as they will raise an fatal error on query cycles instead. -rustc_queries! { - Other { - query trigger_delay_span_bug(key: DefId) -> () { - desc { "trigger a delay span bug" } - } - } - - Other { - // Represents crate as a whole (as distinct from the top-level crate module). - // If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`), - // we will have to assume that any change means that you need to be recompiled. - // This is because the `hir_crate` query gives you access to all other items. - // To avoid this fate, do not call `tcx.hir().krate()`; instead, - // prefer wrappers like `tcx.visit_all_items_in_krate()`. - query hir_crate(key: CrateNum) -> &'tcx Crate<'tcx> { - eval_always - no_hash - desc { "get the crate HIR" } - } - - /// Records the type of every item. - query type_of(key: DefId) -> Ty<'tcx> { - cache_on_disk_if { key.is_local() } - } - - /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its - /// associated generics. - query generics_of(key: DefId) -> &'tcx ty::Generics { - cache_on_disk_if { key.is_local() } - load_cached(tcx, id) { - let generics: Option<ty::Generics> = tcx.queries.on_disk_cache - .try_load_query_result(tcx, id); - generics.map(|x| &*tcx.arena.alloc(x)) - } - } - - /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the - /// predicates (where-clauses) that must be proven true in order - /// to reference it. This is almost always the "predicates query" - /// that you want. - /// - /// `predicates_of` builds on `predicates_defined_on` -- in fact, - /// it is almost always the same as that query, except for the - /// case of traits. For traits, `predicates_of` contains - /// an additional `Self: Trait<...>` predicate that users don't - /// actually write. This reflects the fact that to invoke the - /// trait (e.g., via `Default::default`) you must supply types - /// that actually implement the trait. (However, this extra - /// predicate gets in the way of some checks, which are intended - /// to operate over only the actual where-clauses written by the - /// user.) - query predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { - cache_on_disk_if { key.is_local() } - } - - query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLibrary>> { - desc { "looking up the native libraries of a linked crate" } - } - - query lint_levels(_: CrateNum) -> &'tcx LintLevelMap { - eval_always - desc { "computing the lint levels for items in this crate" } - } - } - - Codegen { - query is_panic_runtime(_: CrateNum) -> bool { - fatal_cycle - desc { "checking if the crate is_panic_runtime" } - } - } - - Codegen { - /// Set of all the `DefId`s in this crate that have MIR associated with - /// them. This includes all the body owners, but also things like struct - /// constructors. - query mir_keys(_: CrateNum) -> &'tcx DefIdSet { - desc { "getting a list of all mir_keys" } - } - - /// Maps DefId's that have an associated `mir::Body` to the result - /// of the MIR const-checking pass. This is the set of qualifs in - /// the final value of a `const`. - query mir_const_qualif(key: DefId) -> mir::ConstQualifs { - desc { |tcx| "const checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } - } - - /// Fetch the MIR for a given `DefId` right after it's built - this includes - /// unreachable code. - query mir_built(_: DefId) -> &'tcx Steal<mir::BodyAndCache<'tcx>> { - desc { "building MIR for" } - } - - /// Fetch the MIR for a given `DefId` up till the point where it is - /// ready for const evaluation. - /// - /// See the README for the `mir` module for details. - query mir_const(_: DefId) -> &'tcx Steal<mir::BodyAndCache<'tcx>> { - no_hash - } - - query mir_validated(_: DefId) -> - ( - &'tcx Steal<mir::BodyAndCache<'tcx>>, - &'tcx Steal<IndexVec<mir::Promoted, mir::BodyAndCache<'tcx>>> - ) { - no_hash - } - - /// MIR after our optimization passes have run. This is MIR that is ready - /// for codegen. This is also the only query that can fetch non-local MIR, at present. - query optimized_mir(key: DefId) -> &'tcx mir::BodyAndCache<'tcx> { - cache_on_disk_if { key.is_local() } - load_cached(tcx, id) { - let mir: Option<crate::mir::BodyAndCache<'tcx>> - = tcx.queries.on_disk_cache.try_load_query_result(tcx, id); - mir.map(|x| { - let cache = tcx.arena.alloc(x); - cache.ensure_predecessors(); - &*cache - }) - } - } - - query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::BodyAndCache<'tcx>> { - cache_on_disk_if { key.is_local() } - load_cached(tcx, id) { - let promoted: Option< - rustc_index::vec::IndexVec< - crate::mir::Promoted, - crate::mir::BodyAndCache<'tcx> - >> = tcx.queries.on_disk_cache.try_load_query_result(tcx, id); - promoted.map(|p| { - let cache = tcx.arena.alloc(p); - for body in cache.iter_mut() { - body.ensure_predecessors(); - } - &*cache - }) - } - } - } - - TypeChecking { - // Erases regions from `ty` to yield a new type. - // Normally you would just use `tcx.erase_regions(&value)`, - // however, which uses this query as a kind of cache. - query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { - // This query is not expected to have input -- as a result, it - // is not a good candidates for "replay" because it is essentially a - // pure function of its input (and hence the expectation is that - // no caller would be green **apart** from just these - // queries). Making it anonymous avoids hashing the result, which - // may save a bit of time. - anon - no_force - desc { "erasing regions from `{:?}`", ty } - } - - query program_clauses_for(_: DefId) -> Clauses<'tcx> { - desc { "generating chalk-style clauses" } - } - - query program_clauses_for_env(_: traits::Environment<'tcx>) -> Clauses<'tcx> { - no_force - desc { "generating chalk-style clauses for environment" } - } - - // Get the chalk-style environment of the given item. - query environment(_: DefId) -> traits::Environment<'tcx> { - desc { "return a chalk-style environment" } - } - } - - Linking { - query wasm_import_module_map(_: CrateNum) -> &'tcx FxHashMap<DefId, String> { - desc { "wasm import module map" } - } - } - - Other { - /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the - /// predicates (where-clauses) directly defined on it. This is - /// equal to the `explicit_predicates_of` predicates plus the - /// `inferred_outlives_of` predicates. - query predicates_defined_on(_: DefId) -> ty::GenericPredicates<'tcx> {} - - /// Returns the predicates written explicitly by the user. - query explicit_predicates_of(_: DefId) -> ty::GenericPredicates<'tcx> {} - - /// Returns the inferred outlives predicates (e.g., for `struct - /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). - query inferred_outlives_of(_: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {} - - /// Maps from the `DefId` of a trait to the list of - /// super-predicates. This is a subset of the full list of - /// predicates. We store these in a separate map because we must - /// evaluate them even during type conversion, often before the - /// full predicates are available (note that supertraits have - /// additional acyclicity requirements). - query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) } - } - - /// To avoid cycles within the predicates of a single item we compute - /// per-type-parameter predicates for resolving `T::AssocTy`. - query type_param_predicates(key: (DefId, DefId)) -> ty::GenericPredicates<'tcx> { - no_force - desc { |tcx| "computing the bounds for type parameter `{}`", { - let id = tcx.hir().as_local_hir_id(key.1).unwrap(); - tcx.hir().ty_param_name(id) - }} - } - - query trait_def(_: DefId) -> &'tcx ty::TraitDef {} - query adt_def(_: DefId) -> &'tcx ty::AdtDef {} - query adt_destructor(_: DefId) -> Option<ty::Destructor> {} - - // The cycle error here should be reported as an error by `check_representable`. - // We consider the type as Sized in the meanwhile to avoid - // further errors (done in impl Value for AdtSizedConstraint). - // Use `cycle_delay_bug` to delay the cycle error here to be emitted later - // in case we accidentally otherwise don't emit an error. - query adt_sized_constraint( - _: DefId - ) -> AdtSizedConstraint<'tcx> { - cycle_delay_bug - } - - query adt_dtorck_constraint( - _: DefId - ) -> Result<DtorckConstraint<'tcx>, NoSolution> {} - - /// Returns `true` if this is a const fn, use the `is_const_fn` to know whether your crate - /// actually sees it as const fn (e.g., the const-fn-ness might be unstable and you might - /// not have the feature gate active). - /// - /// **Do not call this function manually.** It is only meant to cache the base data for the - /// `is_const_fn` function. - query is_const_fn_raw(key: DefId) -> bool { - desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) } - } - - /// Returns `true` if this is a const `impl`. **Do not call this function manually.** - /// - /// This query caches the base data for the `is_const_impl` helper function, which also - /// takes into account stability attributes (e.g., `#[rustc_const_unstable]`). - query is_const_impl_raw(key: DefId) -> bool { - desc { |tcx| "checking if item is const impl: `{}`", tcx.def_path_str(key) } - } - - query asyncness(key: DefId) -> hir::IsAsync { - desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) } - } - - /// Returns `true` if calls to the function may be promoted. - /// - /// This is either because the function is e.g., a tuple-struct or tuple-variant - /// constructor, or because it has the `#[rustc_promotable]` attribute. The attribute should - /// be removed in the future in favour of some form of check which figures out whether the - /// function does not inspect the bits of any of its arguments (so is essentially just a - /// constructor function). - query is_promotable_const_fn(_: DefId) -> bool {} - - query const_fn_is_allowed_fn_ptr(_: DefId) -> bool {} - - /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`). - query is_foreign_item(_: DefId) -> bool {} - - /// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item. - query static_mutability(_: DefId) -> Option<hir::Mutability> {} - - /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator. - query generator_kind(_: DefId) -> Option<hir::GeneratorKind> {} - - /// Gets a map with the variance of every item; use `item_variance` instead. - query crate_variances(_: CrateNum) -> &'tcx ty::CrateVariancesMap<'tcx> { - desc { "computing the variances for items in this crate" } - } - - /// Maps from the `DefId` of a type or region parameter to its (inferred) variance. - query variances_of(_: DefId) -> &'tcx [ty::Variance] {} - } - - TypeChecking { - /// Maps from thee `DefId` of a type to its (inferred) outlives. - query inferred_outlives_crate(_: CrateNum) - -> &'tcx ty::CratePredicatesMap<'tcx> { - desc { "computing the inferred outlives predicates for items in this crate" } - } - } - - Other { - /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items. - query associated_item_def_ids(_: DefId) -> &'tcx [DefId] {} - - /// Maps from a trait item to the trait item "descriptor". - query associated_item(_: DefId) -> ty::AssocItem {} - - /// Collects the associated items defined on a trait or impl. - query associated_items(key: DefId) -> &'tcx ty::AssociatedItems { - desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) } - } - - query impl_trait_ref(_: DefId) -> Option<ty::TraitRef<'tcx>> {} - query impl_polarity(_: DefId) -> ty::ImplPolarity {} - - query issue33140_self_ty(_: DefId) -> Option<ty::Ty<'tcx>> {} - } - - TypeChecking { - /// Maps a `DefId` of a type to a list of its inherent impls. - /// Contains implementations of methods that are inherent to a type. - /// Methods in these implementations don't need to be exported. - query inherent_impls(_: DefId) -> &'tcx [DefId] { - eval_always - } - } - - TypeChecking { - /// The result of unsafety-checking this `DefId`. - query unsafety_check_result(key: DefId) -> mir::UnsafetyCheckResult { - desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } - } - - /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error - query unsafe_derive_on_repr_packed(_: DefId) -> () {} - - /// The signature of functions and closures. - query fn_sig(_: DefId) -> ty::PolyFnSig<'tcx> {} - } - - Other { - query lint_mod(key: DefId) -> () { - desc { |tcx| "linting {}", describe_as_module(key, tcx) } - } - - /// Checks the attributes in the module. - query check_mod_attrs(key: DefId) -> () { - desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) } - } - - query check_mod_unstable_api_usage(key: DefId) -> () { - desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) } - } - - /// Checks the const bodies in the module for illegal operations (e.g. `if` or `loop`). - query check_mod_const_bodies(key: DefId) -> () { - desc { |tcx| "checking consts in {}", describe_as_module(key, tcx) } - } - - /// Checks the loops in the module. - query check_mod_loops(key: DefId) -> () { - desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } - } - - query check_mod_item_types(key: DefId) -> () { - desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) } - } - - query check_mod_privacy(key: DefId) -> () { - desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) } - } - - query check_mod_intrinsics(key: DefId) -> () { - desc { |tcx| "checking intrinsics in {}", describe_as_module(key, tcx) } - } - - query check_mod_liveness(key: DefId) -> () { - desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) } - } - - query check_mod_impl_wf(key: DefId) -> () { - desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) } - } - - query collect_mod_item_types(key: DefId) -> () { - desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) } - } - - /// Caches `CoerceUnsized` kinds for impls on custom types. - query coerce_unsized_info(_: DefId) - -> ty::adjustment::CoerceUnsizedInfo {} - } - - TypeChecking { - query typeck_item_bodies(_: CrateNum) -> () { - desc { "type-checking all item bodies" } - } - - query typeck_tables_of(key: DefId) -> &'tcx ty::TypeckTables<'tcx> { - desc { |tcx| "type-checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } - } - query diagnostic_only_typeck_tables_of(key: DefId) -> &'tcx ty::TypeckTables<'tcx> { - cache_on_disk_if { key.is_local() } - load_cached(tcx, id) { - let typeck_tables: Option<ty::TypeckTables<'tcx>> = tcx - .queries.on_disk_cache - .try_load_query_result(tcx, id); - - typeck_tables.map(|tables| &*tcx.arena.alloc(tables)) - } - } - } - - Other { - query used_trait_imports(key: DefId) -> &'tcx DefIdSet { - cache_on_disk_if { key.is_local() } - } - } - - TypeChecking { - query has_typeck_tables(_: DefId) -> bool {} - - query coherent_trait(def_id: DefId) -> () { - desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) } - } - } - - BorrowChecking { - /// Borrow-checks the function body. If this is a closure, returns - /// additional requirements that the closure's creator must verify. - query mir_borrowck(key: DefId) -> &'tcx mir::BorrowCheckResult<'tcx> { - desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if(tcx, opt_result) { - key.is_local() - && (tcx.is_closure(key) - || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty())) - } - } - } - - TypeChecking { - /// Gets a complete map from all types to their inherent impls. - /// Not meant to be used directly outside of coherence. - /// (Defined only for `LOCAL_CRATE`.) - query crate_inherent_impls(k: CrateNum) - -> &'tcx CrateInherentImpls { - eval_always - desc { "all inherent impls defined in crate `{:?}`", k } - } - - /// Checks all types in the crate for overlap in their inherent impls. Reports errors. - /// Not meant to be used directly outside of coherence. - /// (Defined only for `LOCAL_CRATE`.) - query crate_inherent_impls_overlap_check(_: CrateNum) - -> () { - eval_always - desc { "check for overlap between inherent impls defined in this crate" } - } - } - - Other { - /// Evaluates a constant without running sanity checks. - /// - /// **Do not use this** outside const eval. Const eval uses this to break query cycles - /// during validation. Please add a comment to every use site explaining why using - /// `const_eval_validated` isn't sufficient. The returned constant also isn't in a suitable - /// form to be used outside of const eval. - query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> ConstEvalRawResult<'tcx> { - no_force - desc { |tcx| - "const-evaluating `{}`", - tcx.def_path_str(key.value.instance.def.def_id()) - } - } - - /// Results of evaluating const items or constants embedded in - /// other items (such as enum variant explicit discriminants). - /// - /// In contrast to `const_eval_raw` this performs some validation on the constant, and - /// returns a proper constant that is usable by the rest of the compiler. - /// - /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, - /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_promoted`. - query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> ConstEvalResult<'tcx> { - no_force - desc { |tcx| - "const-evaluating + checking `{}`", - tcx.def_path_str(key.value.instance.def.def_id()) - } - cache_on_disk_if(_, opt_result) { - // Only store results without errors - opt_result.map_or(true, |r| r.is_ok()) - } - } - - /// Extracts a field of a (variant of a) const. - query const_field( - key: ty::ParamEnvAnd<'tcx, (&'tcx ty::Const<'tcx>, mir::Field)> - ) -> ConstValue<'tcx> { - no_force - desc { "extract field of const" } - } - - /// Destructure a constant ADT or array into its variant indent and its - /// field values. - query destructure_const( - key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> - ) -> mir::DestructuredConst<'tcx> { - no_force - desc { "destructure constant" } - } - - query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { - no_force - desc { "get a &core::panic::Location referring to a span" } - } - - query lit_to_const( - key: LitToConstInput<'tcx> - ) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { - no_force - desc { "converting literal to const" } - } - } - - TypeChecking { - query check_match(key: DefId) { - cache_on_disk_if { key.is_local() } - } - - /// Performs part of the privacy check and computes "access levels". - query privacy_access_levels(_: CrateNum) -> &'tcx AccessLevels { - eval_always - desc { "privacy access levels" } - } - query check_private_in_public(_: CrateNum) -> () { - eval_always - desc { "checking for private elements in public interfaces" } - } - } - - Other { - query reachable_set(_: CrateNum) -> Lrc<HirIdSet> { - desc { "reachability" } - } - - /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body; - /// in the case of closures, this will be redirected to the enclosing function. - query region_scope_tree(_: DefId) -> &'tcx region::ScopeTree {} - - query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::BodyAndCache<'tcx> { - no_force - desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) } - } - - /// The `symbol_name` query provides the symbol name for calling a - /// given instance from the local crate. In particular, it will also - /// look up the correct symbol name of instances from upstream crates. - query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName { - no_force - desc { "computing the symbol for `{}`", key } - cache_on_disk_if { true } - } - - query def_kind(_: DefId) -> Option<DefKind> {} - query def_span(_: DefId) -> Span { - // FIXME(mw): DefSpans are not really inputs since they are derived from - // HIR. But at the moment HIR hashing still contains some hacks that allow - // to make type debuginfo to be source location independent. Declaring - // DefSpan an input makes sure that changes to these are always detected - // regardless of HIR hashing. - eval_always - } - query lookup_stability(_: DefId) -> Option<&'tcx attr::Stability> {} - query lookup_const_stability(_: DefId) -> Option<&'tcx attr::ConstStability> {} - query lookup_deprecation_entry(_: DefId) -> Option<DeprecationEntry> {} - query item_attrs(_: DefId) -> Lrc<[ast::Attribute]> {} - } - - Codegen { - query codegen_fn_attrs(_: DefId) -> CodegenFnAttrs { - cache_on_disk_if { true } - } - } - - Other { - query fn_arg_names(_: DefId) -> Vec<ast::Name> {} - /// Gets the rendered value of the specified constant or associated constant. - /// Used by rustdoc. - query rendered_const(_: DefId) -> String {} - query impl_parent(_: DefId) -> Option<DefId> {} - } - - TypeChecking { - query trait_of_item(_: DefId) -> Option<DefId> {} - } - - Codegen { - query is_mir_available(key: DefId) -> bool { - desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) } - } - } - - Other { - query vtable_methods(key: ty::PolyTraitRef<'tcx>) - -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { - no_force - desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) } - } - } - - Codegen { - query codegen_fulfill_obligation( - key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) - ) -> Vtable<'tcx, ()> { - no_force - cache_on_disk_if { true } - desc { |tcx| - "checking if `{}` fulfills its obligations", - tcx.def_path_str(key.1.def_id()) - } - } - } - - TypeChecking { - query trait_impls_of(key: DefId) -> &'tcx ty::trait_def::TraitImpls { - desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) } - } - query specialization_graph_of(key: DefId) -> &'tcx specialization_graph::Graph { - desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(key) } - cache_on_disk_if { true } - } - query object_safety_violations(key: DefId) -> Vec<traits::ObjectSafetyViolation> { - desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) } - } - - /// Gets the ParameterEnvironment for a given item; this environment - /// will be in "user-facing" mode, meaning that it is suitabe for - /// type-checking etc, and it does not normalize specializable - /// associated types. This is almost always what you want, - /// unless you are doing MIR optimizations, in which case you - /// might want to use `reveal_all()` method to change modes. - query param_env(_: DefId) -> ty::ParamEnv<'tcx> {} - - /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`, - /// `ty.is_copy()`, etc, since that will prune the environment where possible. - query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - no_force - desc { "computing whether `{}` is `Copy`", env.value } - } - /// Query backing `TyS::is_sized`. - query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - no_force - desc { "computing whether `{}` is `Sized`", env.value } - } - /// Query backing `TyS::is_freeze`. - query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - no_force - desc { "computing whether `{}` is freeze", env.value } - } - /// Query backing `TyS::needs_drop`. - query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - no_force - desc { "computing whether `{}` needs drop", env.value } - } - - /// A list of types where the ADT requires drop if and only if any of - /// those types require drop. If the ADT is known to always need drop - /// then `Err(AlwaysRequiresDrop)` is returned. - query adt_drop_tys(_: DefId) -> Result<&'tcx ty::List<Ty<'tcx>>, AlwaysRequiresDrop> { - cache_on_disk_if { true } - } - - query layout_raw( - env: ty::ParamEnvAnd<'tcx, Ty<'tcx>> - ) -> Result<&'tcx ty::layout::LayoutDetails, ty::layout::LayoutError<'tcx>> { - no_force - desc { "computing layout of `{}`", env.value } - } - } - - Other { - query dylib_dependency_formats(_: CrateNum) - -> &'tcx [(CrateNum, LinkagePreference)] { - desc { "dylib dependency formats of crate" } - } - - query dependency_formats(_: CrateNum) - -> Lrc<crate::middle::dependency_format::Dependencies> - { - desc { "get the linkage format of all dependencies" } - } - } - - Codegen { - query is_compiler_builtins(_: CrateNum) -> bool { - fatal_cycle - desc { "checking if the crate is_compiler_builtins" } - } - query has_global_allocator(_: CrateNum) -> bool { - fatal_cycle - desc { "checking if the crate has_global_allocator" } - } - query has_panic_handler(_: CrateNum) -> bool { - fatal_cycle - desc { "checking if the crate has_panic_handler" } - } - query is_profiler_runtime(_: CrateNum) -> bool { - fatal_cycle - desc { "query a crate is `#![profiler_runtime]`" } - } - query panic_strategy(_: CrateNum) -> PanicStrategy { - fatal_cycle - desc { "query a crate's configured panic strategy" } - } - query is_no_builtins(_: CrateNum) -> bool { - fatal_cycle - desc { "test whether a crate has `#![no_builtins]`" } - } - query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion { - fatal_cycle - desc { "query a crate's symbol mangling version" } - } - - query extern_crate(_: DefId) -> Option<&'tcx ExternCrate> { - eval_always - desc { "getting crate's ExternCrateData" } - } - } - - TypeChecking { - query specializes(_: (DefId, DefId)) -> bool { - no_force - desc { "computing whether impls specialize one another" } - } - query in_scope_traits_map(_: DefIndex) - -> Option<&'tcx FxHashMap<ItemLocalId, StableVec<TraitCandidate>>> { - eval_always - desc { "traits in scope at a block" } - } - } - - Other { - query module_exports(_: DefId) -> Option<&'tcx [Export<hir::HirId>]> { - eval_always - } - } - - TypeChecking { - query impl_defaultness(_: DefId) -> hir::Defaultness {} - - query check_item_well_formed(_: DefId) -> () {} - query check_trait_item_well_formed(_: DefId) -> () {} - query check_impl_item_well_formed(_: DefId) -> () {} - } - - Linking { - // The `DefId`s of all non-generic functions and statics in the given crate - // that can be reached from outside the crate. - // - // We expect this items to be available for being linked to. - // - // This query can also be called for `LOCAL_CRATE`. In this case it will - // compute which items will be reachable to other crates, taking into account - // the kind of crate that is currently compiled. Crates with only a - // C interface have fewer reachable things. - // - // Does not include external symbols that don't have a corresponding DefId, - // like the compiler-generated `main` function and so on. - query reachable_non_generics(_: CrateNum) - -> &'tcx DefIdMap<SymbolExportLevel> { - desc { "looking up the exported symbols of a crate" } - } - query is_reachable_non_generic(_: DefId) -> bool {} - query is_unreachable_local_definition(_: DefId) -> bool {} - } - - Codegen { - /// The entire set of monomorphizations the local crate can safely link - /// to because they are exported from upstream crates. Do not depend on - /// this directly, as its value changes anytime a monomorphization gets - /// added or removed in any upstream crate. Instead use the narrower - /// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even - /// better, `Instance::upstream_monomorphization()`. - query upstream_monomorphizations( - k: CrateNum - ) -> &'tcx DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> { - desc { "collecting available upstream monomorphizations `{:?}`", k } - } - - /// Returns the set of upstream monomorphizations available for the - /// generic function identified by the given `def_id`. The query makes - /// sure to make a stable selection if the same monomorphization is - /// available in multiple upstream crates. - /// - /// You likely want to call `Instance::upstream_monomorphization()` - /// instead of invoking this query directly. - query upstream_monomorphizations_for(_: DefId) - -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>> {} - - /// Returns the upstream crate that exports drop-glue for the given - /// type (`substs` is expected to be a single-item list containing the - /// type one wants drop-glue for). - /// - /// This is a subset of `upstream_monomorphizations_for` in order to - /// increase dep-tracking granularity. Otherwise adding or removing any - /// type with drop-glue in any upstream crate would invalidate all - /// functions calling drop-glue of an upstream type. - /// - /// You likely want to call `Instance::upstream_monomorphization()` - /// instead of invoking this query directly. - /// - /// NOTE: This query could easily be extended to also support other - /// common functions that have are large set of monomorphizations - /// (like `Clone::clone` for example). - query upstream_drop_glue_for(substs: SubstsRef<'tcx>) -> Option<CrateNum> { - desc { "available upstream drop-glue for `{:?}`", substs } - no_force - } - } - - Other { - query foreign_modules(_: CrateNum) -> &'tcx [ForeignModule] { - desc { "looking up the foreign modules of a linked crate" } - } - - /// Identifies the entry-point (e.g., the `main` function) for a given - /// crate, returning `None` if there is no entry point (such as for library crates). - query entry_fn(_: CrateNum) -> Option<(DefId, EntryFnType)> { - desc { "looking up the entry function of a crate" } - } - query plugin_registrar_fn(_: CrateNum) -> Option<DefId> { - desc { "looking up the plugin registrar for a crate" } - } - query proc_macro_decls_static(_: CrateNum) -> Option<DefId> { - desc { "looking up the derive registrar for a crate" } - } - query crate_disambiguator(_: CrateNum) -> CrateDisambiguator { - eval_always - desc { "looking up the disambiguator a crate" } - } - query crate_hash(_: CrateNum) -> Svh { - eval_always - desc { "looking up the hash a crate" } - } - query crate_host_hash(_: CrateNum) -> Option<Svh> { - eval_always - desc { "looking up the hash of a host version of a crate" } - } - query original_crate_name(_: CrateNum) -> Symbol { - eval_always - desc { "looking up the original name a crate" } - } - query extra_filename(_: CrateNum) -> String { - eval_always - desc { "looking up the extra filename for a crate" } - } - } - - TypeChecking { - query implementations_of_trait(_: (CrateNum, DefId)) - -> &'tcx [DefId] { - no_force - desc { "looking up implementations of a trait in a crate" } - } - query all_trait_implementations(_: CrateNum) - -> &'tcx [DefId] { - desc { "looking up all (?) trait implementations" } - } - } - - Other { - query dllimport_foreign_items(_: CrateNum) - -> &'tcx FxHashSet<DefId> { - desc { "dllimport_foreign_items" } - } - query is_dllimport_foreign_item(_: DefId) -> bool {} - query is_statically_included_foreign_item(_: DefId) -> bool {} - query native_library_kind(_: DefId) - -> Option<NativeLibraryKind> {} - } - - Linking { - query link_args(_: CrateNum) -> Lrc<Vec<String>> { - eval_always - desc { "looking up link arguments for a crate" } - } - } - - BorrowChecking { - /// Lifetime resolution. See `middle::resolve_lifetimes`. - query resolve_lifetimes(_: CrateNum) -> &'tcx ResolveLifetimes { - desc { "resolving lifetimes" } - } - query named_region_map(_: DefIndex) -> - Option<&'tcx FxHashMap<ItemLocalId, Region>> { - desc { "looking up a named region" } - } - query is_late_bound_map(_: DefIndex) -> - Option<&'tcx FxHashSet<ItemLocalId>> { - desc { "testing if a region is late bound" } - } - query object_lifetime_defaults_map(_: DefIndex) - -> Option<&'tcx FxHashMap<ItemLocalId, Vec<ObjectLifetimeDefault>>> { - desc { "looking up lifetime defaults for a region" } - } - } - - TypeChecking { - query visibility(_: DefId) -> ty::Visibility {} - } - - Other { - query dep_kind(_: CrateNum) -> DepKind { - eval_always - desc { "fetching what a dependency looks like" } - } - query crate_name(_: CrateNum) -> Symbol { - eval_always - desc { "fetching what a crate is named" } - } - query item_children(_: DefId) -> &'tcx [Export<hir::HirId>] {} - query extern_mod_stmt_cnum(_: DefId) -> Option<CrateNum> {} - - query get_lib_features(_: CrateNum) -> &'tcx LibFeatures { - eval_always - desc { "calculating the lib features map" } - } - query defined_lib_features(_: CrateNum) - -> &'tcx [(Symbol, Option<Symbol>)] { - desc { "calculating the lib features defined in a crate" } - } - /// Returns the lang items defined in another crate by loading it from metadata. - // FIXME: It is illegal to pass a `CrateNum` other than `LOCAL_CRATE` here, just get rid - // of that argument? - query get_lang_items(_: CrateNum) -> &'tcx LanguageItems { - eval_always - desc { "calculating the lang items map" } - } - - /// Returns all diagnostic items defined in all crates. - query all_diagnostic_items(_: CrateNum) -> &'tcx FxHashMap<Symbol, DefId> { - eval_always - desc { "calculating the diagnostic items map" } - } - - /// Returns the lang items defined in another crate by loading it from metadata. - query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] { - desc { "calculating the lang items defined in a crate" } - } - - /// Returns the diagnostic items defined in a crate. - query diagnostic_items(_: CrateNum) -> &'tcx FxHashMap<Symbol, DefId> { - desc { "calculating the diagnostic items map in a crate" } - } - - query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] { - desc { "calculating the missing lang items in a crate" } - } - query visible_parent_map(_: CrateNum) - -> &'tcx DefIdMap<DefId> { - desc { "calculating the visible parent map" } - } - query missing_extern_crate_item(_: CrateNum) -> bool { - eval_always - desc { "seeing if we're missing an `extern crate` item for this crate" } - } - query used_crate_source(_: CrateNum) -> Lrc<CrateSource> { - eval_always - desc { "looking at the source for a crate" } - } - query postorder_cnums(_: CrateNum) -> &'tcx [CrateNum] { - eval_always - desc { "generating a postorder list of CrateNums" } - } - - query upvars(_: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> { - eval_always - } - query maybe_unused_trait_import(_: DefId) -> bool { - eval_always - } - query maybe_unused_extern_crates(_: CrateNum) - -> &'tcx [(DefId, Span)] { - eval_always - desc { "looking up all possibly unused extern crates" } - } - query names_imported_by_glob_use(_: DefId) - -> Lrc<FxHashSet<ast::Name>> { - eval_always - } - - query stability_index(_: CrateNum) -> &'tcx stability::Index<'tcx> { - eval_always - desc { "calculating the stability index for the local crate" } - } - query all_crate_nums(_: CrateNum) -> &'tcx [CrateNum] { - eval_always - desc { "fetching all foreign CrateNum instances" } - } - - /// A vector of every trait accessible in the whole crate - /// (i.e., including those from subcrates). This is used only for - /// error reporting. - query all_traits(_: CrateNum) -> &'tcx [DefId] { - desc { "fetching all foreign and local traits" } - } - } - - Linking { - /// The list of symbols exported from the given crate. - /// - /// - All names contained in `exported_symbols(cnum)` are guaranteed to - /// correspond to a publicly visible symbol in `cnum` machine code. - /// - The `exported_symbols` sets of different crates do not intersect. - query exported_symbols(_: CrateNum) - -> Arc<Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)>> { - desc { "exported_symbols" } - } - } - - Codegen { - query collect_and_partition_mono_items(_: CrateNum) - -> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>) { - eval_always - desc { "collect_and_partition_mono_items" } - } - query is_codegened_item(_: DefId) -> bool {} - query codegen_unit(_: Symbol) -> Arc<CodegenUnit<'tcx>> { - no_force - desc { "codegen_unit" } - } - query backend_optimization_level(_: CrateNum) -> OptLevel { - desc { "optimization level used by backend" } - } - } - - Other { - query output_filenames(_: CrateNum) -> Arc<OutputFilenames> { - eval_always - desc { "output_filenames" } - } - } - - TypeChecking { - /// Do not call this query directly: invoke `normalize` instead. - query normalize_projection_ty( - goal: CanonicalProjectionGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, - NoSolution, - > { - no_force - desc { "normalizing `{:?}`", goal } - } - - /// Do not call this query directly: invoke `normalize_erasing_regions` instead. - query normalize_ty_after_erasing_regions( - goal: ParamEnvAnd<'tcx, Ty<'tcx>> - ) -> Ty<'tcx> { - no_force - desc { "normalizing `{:?}`", goal } - } - - query implied_outlives_bounds( - goal: CanonicalTyGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>, - NoSolution, - > { - no_force - desc { "computing implied outlives bounds for `{:?}`", goal } - } - - /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. - query dropck_outlives( - goal: CanonicalTyGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, - NoSolution, - > { - no_force - desc { "computing dropck types for `{:?}`", goal } - } - - /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or - /// `infcx.predicate_must_hold()` instead. - query evaluate_obligation( - goal: CanonicalPredicateGoal<'tcx> - ) -> Result<traits::EvaluationResult, traits::OverflowError> { - no_force - desc { "evaluating trait selection obligation `{}`", goal.value.value } - } - - query evaluate_goal( - goal: traits::ChalkCanonicalGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, - NoSolution - > { - no_force - desc { "evaluating trait selection obligation `{}`", goal.value.goal } - } - - /// Do not call this query directly: part of the `Eq` type-op - query type_op_ascribe_user_type( - goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, - NoSolution, - > { - no_force - desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal } - } - - /// Do not call this query directly: part of the `Eq` type-op - query type_op_eq( - goal: CanonicalTypeOpEqGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, - NoSolution, - > { - no_force - desc { "evaluating `type_op_eq` `{:?}`", goal } - } - - /// Do not call this query directly: part of the `Subtype` type-op - query type_op_subtype( - goal: CanonicalTypeOpSubtypeGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, - NoSolution, - > { - no_force - desc { "evaluating `type_op_subtype` `{:?}`", goal } - } - - /// Do not call this query directly: part of the `ProvePredicate` type-op - query type_op_prove_predicate( - goal: CanonicalTypeOpProvePredicateGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, - NoSolution, - > { - no_force - desc { "evaluating `type_op_prove_predicate` `{:?}`", goal } - } - - /// Do not call this query directly: part of the `Normalize` type-op - query type_op_normalize_ty( - goal: CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>, - NoSolution, - > { - no_force - desc { "normalizing `{:?}`", goal } - } - - /// Do not call this query directly: part of the `Normalize` type-op - query type_op_normalize_predicate( - goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>, - NoSolution, - > { - no_force - desc { "normalizing `{:?}`", goal } - } - - /// Do not call this query directly: part of the `Normalize` type-op - query type_op_normalize_poly_fn_sig( - goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>, - NoSolution, - > { - no_force - desc { "normalizing `{:?}`", goal } - } - - /// Do not call this query directly: part of the `Normalize` type-op - query type_op_normalize_fn_sig( - goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>, - NoSolution, - > { - no_force - desc { "normalizing `{:?}`", goal } - } - - query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool { - no_force - desc { |tcx| - "testing substituted normalized predicates:`{}`", - tcx.def_path_str(key.0) - } - } - - query method_autoderef_steps( - goal: CanonicalTyGoal<'tcx> - ) -> MethodAutoderefStepsResult<'tcx> { - no_force - desc { "computing autoderef types for `{:?}`", goal } - } - } - - Other { - query target_features_whitelist(_: CrateNum) -> &'tcx FxHashMap<String, Option<Symbol>> { - eval_always - desc { "looking up the whitelist of target features" } - } - - // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. - query instance_def_size_estimate(def: ty::InstanceDef<'tcx>) - -> usize { - no_force - desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) } - } - - query features_query(_: CrateNum) -> &'tcx rustc_feature::Features { - eval_always - desc { "looking up enabled feature gates" } - } - } -} diff --git a/src/librustc/tests.rs b/src/librustc/tests.rs deleted file mode 100644 index cf3ea2ffa93..00000000000 --- a/src/librustc/tests.rs +++ /dev/null @@ -1,13 +0,0 @@ -use super::*; - -// FIXME(#27438): right now the unit tests of librustc don't refer to any actual -// functions generated in librustc_data_structures (all -// references are through generic functions), but statics are -// referenced from time to time. Due to this bug we won't -// actually correctly link in the statics unless we also -// reference a function, so be sure to reference a dummy -// function. -#[test] -fn noop() { - rustc_data_structures::__noop_fix_for_27438(); -} diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs deleted file mode 100644 index de2ec53e51e..00000000000 --- a/src/librustc/traits/mod.rs +++ /dev/null @@ -1,871 +0,0 @@ -//! Trait Resolution. See the [rustc guide] for more information on how this works. -//! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html - -pub mod query; -pub mod select; -pub mod specialization_graph; -mod structural_impls; - -use crate::infer::canonical::Canonical; -use crate::mir::interpret::ErrorHandled; -use crate::ty::fold::{TypeFolder, TypeVisitor}; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, AdtKind, List, Ty, TyCtxt}; - -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_span::{Span, DUMMY_SP}; -use smallvec::SmallVec; -use syntax::ast; - -use std::borrow::Cow; -use std::fmt::Debug; -use std::rc::Rc; - -pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; - -pub type ChalkCanonicalGoal<'tcx> = Canonical<'tcx, InEnvironment<'tcx, ty::Predicate<'tcx>>>; - -pub use self::ObligationCauseCode::*; -pub use self::SelectionError::*; -pub use self::Vtable::*; - -/// Depending on the stage of compilation, we want projection to be -/// more or less conservative. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] -pub enum Reveal { - /// At type-checking time, we refuse to project any associated - /// type that is marked `default`. Non-`default` ("final") types - /// are always projected. This is necessary in general for - /// soundness of specialization. However, we *could* allow - /// projections in fully-monomorphic cases. We choose not to, - /// because we prefer for `default type` to force the type - /// definition to be treated abstractly by any consumers of the - /// impl. Concretely, that means that the following example will - /// fail to compile: - /// - /// ``` - /// trait Assoc { - /// type Output; - /// } - /// - /// impl<T> Assoc for T { - /// default type Output = bool; - /// } - /// - /// fn main() { - /// let <() as Assoc>::Output = true; - /// } - /// ``` - UserFacing, - - /// At codegen time, all monomorphic projections will succeed. - /// Also, `impl Trait` is normalized to the concrete type, - /// which has to be already collected by type-checking. - /// - /// NOTE: as `impl Trait`'s concrete type should *never* - /// be observable directly by the user, `Reveal::All` - /// should not be used by checks which may expose - /// type equality or type contents to the user. - /// There are some exceptions, e.g., around OIBITS and - /// transmute-checking, which expose some details, but - /// not the whole concrete type of the `impl Trait`. - All, -} - -/// The reason why we incurred this obligation; used for error reporting. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct ObligationCause<'tcx> { - pub span: Span, - - /// The ID of the fn body that triggered this obligation. This is - /// used for region obligations to determine the precise - /// environment in which the region obligation should be evaluated - /// (in particular, closures can add new assumptions). See the - /// field `region_obligations` of the `FulfillmentContext` for more - /// information. - pub body_id: hir::HirId, - - pub code: ObligationCauseCode<'tcx>, -} - -impl<'tcx> ObligationCause<'tcx> { - #[inline] - pub fn new( - span: Span, - body_id: hir::HirId, - code: ObligationCauseCode<'tcx>, - ) -> ObligationCause<'tcx> { - ObligationCause { span, body_id, code } - } - - pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> { - ObligationCause { span, body_id, code: MiscObligation } - } - - pub fn dummy() -> ObligationCause<'tcx> { - ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation } - } - - pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span { - match self.code { - ObligationCauseCode::CompareImplMethodObligation { .. } - | ObligationCauseCode::MainFunctionType - | ObligationCauseCode::StartFunctionType => tcx.sess.source_map().def_span(self.span), - ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - arm_span, - .. - }) => arm_span, - _ => self.span, - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum ObligationCauseCode<'tcx> { - /// Not well classified or should be obvious from the span. - MiscObligation, - - /// A slice or array is WF only if `T: Sized`. - SliceOrArrayElem, - - /// A tuple is WF only if its middle elements are `Sized`. - TupleElem, - - /// This is the trait reference from the given projection. - ProjectionWf(ty::ProjectionTy<'tcx>), - - /// In an impl of trait `X` for type `Y`, type `Y` must - /// also implement all supertraits of `X`. - ItemObligation(DefId), - - /// Like `ItemObligation`, but with extra detail on the source of the obligation. - BindingObligation(DefId, Span), - - /// A type like `&'a T` is WF only if `T: 'a`. - ReferenceOutlivesReferent(Ty<'tcx>), - - /// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`. - ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>), - - /// Obligation incurred due to an object cast. - ObjectCastObligation(/* Object type */ Ty<'tcx>), - - /// Obligation incurred due to a coercion. - Coercion { - source: Ty<'tcx>, - target: Ty<'tcx>, - }, - - /// Various cases where expressions must be `Sized` / `Copy` / etc. - /// `L = X` implies that `L` is `Sized`. - AssignmentLhsSized, - /// `(x1, .., xn)` must be `Sized`. - TupleInitializerSized, - /// `S { ... }` must be `Sized`. - StructInitializerSized, - /// Type of each variable must be `Sized`. - VariableType(hir::HirId), - /// Argument type must be `Sized`. - SizedArgumentType, - /// Return type must be `Sized`. - SizedReturnType, - /// Yield type must be `Sized`. - SizedYieldType, - /// `[T, ..n]` implies that `T` must be `Copy`. - /// If `true`, suggest `const_in_array_repeat_expressions` feature flag. - RepeatVec(bool), - - /// Types of fields (other than the last, except for packed structs) in a struct must be sized. - FieldSized { - adt_kind: AdtKind, - last: bool, - }, - - /// Constant expressions must be sized. - ConstSized, - - /// `static` items must have `Sync` type. - SharedStatic, - - BuiltinDerivedObligation(DerivedObligationCause<'tcx>), - - ImplDerivedObligation(DerivedObligationCause<'tcx>), - - /// Error derived when matching traits/impls; see ObligationCause for more details - CompareImplMethodObligation { - item_name: ast::Name, - impl_item_def_id: DefId, - trait_item_def_id: DefId, - }, - - /// Error derived when matching traits/impls; see ObligationCause for more details - CompareImplTypeObligation { - item_name: ast::Name, - impl_item_def_id: DefId, - trait_item_def_id: DefId, - }, - - /// Checking that this expression can be assigned where it needs to be - // FIXME(eddyb) #11161 is the original Expr required? - ExprAssignable, - - /// Computing common supertype in the arms of a match expression - MatchExpressionArm(Box<MatchExpressionArmCause<'tcx>>), - - /// Type error arising from type checking a pattern against an expected type. - Pattern { - /// The span of the scrutinee or type expression which caused the `root_ty` type. - span: Option<Span>, - /// The root expected type induced by a scrutinee or type expression. - root_ty: Ty<'tcx>, - /// Whether the `Span` came from an expression or a type expression. - origin_expr: bool, - }, - - /// Constants in patterns must have `Structural` type. - ConstPatternStructural, - - /// Computing common supertype in an if expression - IfExpression(Box<IfExpressionCause>), - - /// Computing common supertype of an if expression with no else counter-part - IfExpressionWithNoElse, - - /// `main` has wrong type - MainFunctionType, - - /// `start` has wrong type - StartFunctionType, - - /// Intrinsic has wrong type - IntrinsicType, - - /// Method receiver - MethodReceiver, - - /// `return` with no expression - ReturnNoExpression, - - /// `return` with an expression - ReturnValue(hir::HirId), - - /// Return type of this function - ReturnType, - - /// Block implicit return - BlockTailExpression(hir::HirId), - - /// #[feature(trivial_bounds)] is not enabled - TrivialBound, - - AssocTypeBound(Box<AssocTypeBoundData>), -} - -impl ObligationCauseCode<'_> { - // Return the base obligation, ignoring derived obligations. - pub fn peel_derives(&self) -> &Self { - let mut base_cause = self; - while let BuiltinDerivedObligation(cause) | ImplDerivedObligation(cause) = base_cause { - base_cause = &cause.parent_code; - } - base_cause - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct AssocTypeBoundData { - pub impl_span: Option<Span>, - pub original: Span, - pub bounds: Vec<Span>, -} - -// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(target_arch = "x86_64")] -static_assert_size!(ObligationCauseCode<'_>, 32); - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct MatchExpressionArmCause<'tcx> { - pub arm_span: Span, - pub source: hir::MatchSource, - pub prior_arms: Vec<Span>, - pub last_ty: Ty<'tcx>, - pub scrut_hir_id: hir::HirId, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct IfExpressionCause { - pub then: Span, - pub outer: Option<Span>, - pub semicolon: Option<Span>, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct DerivedObligationCause<'tcx> { - /// The trait reference of the parent obligation that led to the - /// current obligation. Note that only trait obligations lead to - /// derived obligations, so we just store the trait reference here - /// directly. - pub parent_trait_ref: ty::PolyTraitRef<'tcx>, - - /// The parent trait had this cause. - pub parent_code: Rc<ObligationCauseCode<'tcx>>, -} - -/// The following types: -/// * `WhereClause`, -/// * `WellFormed`, -/// * `FromEnv`, -/// * `DomainGoal`, -/// * `Goal`, -/// * `Clause`, -/// * `Environment`, -/// * `InEnvironment`, -/// are used for representing the trait system in the form of -/// logic programming clauses. They are part of the interface -/// for the chalk SLG solver. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum WhereClause<'tcx> { - Implemented(ty::TraitPredicate<'tcx>), - ProjectionEq(ty::ProjectionPredicate<'tcx>), - RegionOutlives(ty::RegionOutlivesPredicate<'tcx>), - TypeOutlives(ty::TypeOutlivesPredicate<'tcx>), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum WellFormed<'tcx> { - Trait(ty::TraitPredicate<'tcx>), - Ty(Ty<'tcx>), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum FromEnv<'tcx> { - Trait(ty::TraitPredicate<'tcx>), - Ty(Ty<'tcx>), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum DomainGoal<'tcx> { - Holds(WhereClause<'tcx>), - WellFormed(WellFormed<'tcx>), - FromEnv(FromEnv<'tcx>), - Normalize(ty::ProjectionPredicate<'tcx>), -} - -pub type PolyDomainGoal<'tcx> = ty::Binder<DomainGoal<'tcx>>; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)] -pub enum QuantifierKind { - Universal, - Existential, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum GoalKind<'tcx> { - Implies(Clauses<'tcx>, Goal<'tcx>), - And(Goal<'tcx>, Goal<'tcx>), - Not(Goal<'tcx>), - DomainGoal(DomainGoal<'tcx>), - Quantified(QuantifierKind, ty::Binder<Goal<'tcx>>), - Subtype(Ty<'tcx>, Ty<'tcx>), - CannotProve, -} - -pub type Goal<'tcx> = &'tcx GoalKind<'tcx>; - -pub type Goals<'tcx> = &'tcx List<Goal<'tcx>>; - -impl<'tcx> DomainGoal<'tcx> { - pub fn into_goal(self) -> GoalKind<'tcx> { - GoalKind::DomainGoal(self) - } - - pub fn into_program_clause(self) -> ProgramClause<'tcx> { - ProgramClause { - goal: self, - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::Other, - } - } -} - -impl<'tcx> GoalKind<'tcx> { - pub fn from_poly_domain_goal( - domain_goal: PolyDomainGoal<'tcx>, - tcx: TyCtxt<'tcx>, - ) -> GoalKind<'tcx> { - match domain_goal.no_bound_vars() { - Some(p) => p.into_goal(), - None => GoalKind::Quantified( - QuantifierKind::Universal, - domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal())), - ), - } - } -} - -/// This matches the definition from Page 7 of "A Proof Procedure for the Logic of Hereditary -/// Harrop Formulas". -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub enum Clause<'tcx> { - Implies(ProgramClause<'tcx>), - ForAll(ty::Binder<ProgramClause<'tcx>>), -} - -impl Clause<'tcx> { - pub fn category(self) -> ProgramClauseCategory { - match self { - Clause::Implies(clause) => clause.category, - Clause::ForAll(clause) => clause.skip_binder().category, - } - } -} - -/// Multiple clauses. -pub type Clauses<'tcx> = &'tcx List<Clause<'tcx>>; - -/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying -/// that the domain goal `D` is true if `G1...Gn` are provable. This -/// is equivalent to the implication `G1..Gn => D`; we usually write -/// it with the reverse implication operator `:-` to emphasize the way -/// that programs are actually solved (via backchaining, which starts -/// with the goal to solve and proceeds from there). -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub struct ProgramClause<'tcx> { - /// This goal will be considered true ... - pub goal: DomainGoal<'tcx>, - - /// ... if we can prove these hypotheses (there may be no hypotheses at all): - pub hypotheses: Goals<'tcx>, - - /// Useful for filtering clauses. - pub category: ProgramClauseCategory, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)] -pub enum ProgramClauseCategory { - ImpliedBound, - WellFormed, - Other, -} - -/// A set of clauses that we assume to be true. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub struct Environment<'tcx> { - pub clauses: Clauses<'tcx>, -} - -impl Environment<'tcx> { - pub fn with<G>(self, goal: G) -> InEnvironment<'tcx, G> { - InEnvironment { environment: self, goal } - } -} - -/// Something (usually a goal), along with an environment. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub struct InEnvironment<'tcx, G> { - pub environment: Environment<'tcx>, - pub goal: G, -} - -#[derive(Clone, Debug, TypeFoldable)] -pub enum SelectionError<'tcx> { - Unimplemented, - OutputTypeParameterMismatch( - ty::PolyTraitRef<'tcx>, - ty::PolyTraitRef<'tcx>, - ty::error::TypeError<'tcx>, - ), - TraitNotObjectSafe(DefId), - ConstEvalFailure(ErrorHandled), - Overflow, -} - -/// When performing resolution, it is typically the case that there -/// can be one of three outcomes: -/// -/// - `Ok(Some(r))`: success occurred with result `r` -/// - `Ok(None)`: could not definitely determine anything, usually due -/// to inconclusive type inference. -/// - `Err(e)`: error `e` occurred -pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>; - -/// Given the successful resolution of an obligation, the `Vtable` -/// indicates where the vtable comes from. Note that while we call this -/// a "vtable", it does not necessarily indicate dynamic dispatch at -/// runtime. `Vtable` instances just tell the compiler where to find -/// methods, but in generic code those methods are typically statically -/// dispatched -- only when an object is constructed is a `Vtable` -/// instance reified into an actual vtable. -/// -/// For example, the vtable may be tied to a specific impl (case A), -/// or it may be relative to some bound that is in scope (case B). -/// -/// ``` -/// impl<T:Clone> Clone<T> for Option<T> { ... } // Impl_1 -/// impl<T:Clone> Clone<T> for Box<T> { ... } // Impl_2 -/// impl Clone for int { ... } // Impl_3 -/// -/// fn foo<T:Clone>(concrete: Option<Box<int>>, -/// param: T, -/// mixed: Option<T>) { -/// -/// // Case A: Vtable points at a specific impl. Only possible when -/// // type is concretely known. If the impl itself has bounded -/// // type parameters, Vtable will carry resolutions for those as well: -/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])]) -/// -/// // Case B: Vtable must be provided by caller. This applies when -/// // type is a type parameter. -/// param.clone(); // VtableParam -/// -/// // Case C: A mix of cases A and B. -/// mixed.clone(); // Vtable(Impl_1, [VtableParam]) -/// } -/// ``` -/// -/// ### The type parameter `N` -/// -/// See explanation on `VtableImplData`. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub enum Vtable<'tcx, N> { - /// Vtable identifying a particular impl. - VtableImpl(VtableImplData<'tcx, N>), - - /// Vtable for auto trait implementations. - /// This carries the information and nested obligations with regards - /// to an auto implementation for a trait `Trait`. The nested obligations - /// ensure the trait implementation holds for all the constituent types. - VtableAutoImpl(VtableAutoImplData<N>), - - /// Successful resolution to an obligation provided by the caller - /// for some type parameter. The `Vec<N>` represents the - /// obligations incurred from normalizing the where-clause (if - /// any). - VtableParam(Vec<N>), - - /// Virtual calls through an object. - VtableObject(VtableObjectData<'tcx, N>), - - /// Successful resolution for a builtin trait. - VtableBuiltin(VtableBuiltinData<N>), - - /// Vtable automatically generated for a closure. The `DefId` is the ID - /// of the closure expression. This is a `VtableImpl` in spirit, but the - /// impl is generated by the compiler and does not appear in the source. - VtableClosure(VtableClosureData<'tcx, N>), - - /// Same as above, but for a function pointer type with the given signature. - VtableFnPointer(VtableFnPointerData<'tcx, N>), - - /// Vtable automatically generated for a generator. - VtableGenerator(VtableGeneratorData<'tcx, N>), - - /// Vtable for a trait alias. - VtableTraitAlias(VtableTraitAliasData<'tcx, N>), -} - -impl<'tcx, N> Vtable<'tcx, N> { - pub fn nested_obligations(self) -> Vec<N> { - match self { - VtableImpl(i) => i.nested, - VtableParam(n) => n, - VtableBuiltin(i) => i.nested, - VtableAutoImpl(d) => d.nested, - VtableClosure(c) => c.nested, - VtableGenerator(c) => c.nested, - VtableObject(d) => d.nested, - VtableFnPointer(d) => d.nested, - VtableTraitAlias(d) => d.nested, - } - } - - pub fn map<M, F>(self, f: F) -> Vtable<'tcx, M> - where - F: FnMut(N) -> M, - { - match self { - VtableImpl(i) => VtableImpl(VtableImplData { - impl_def_id: i.impl_def_id, - substs: i.substs, - nested: i.nested.into_iter().map(f).collect(), - }), - VtableParam(n) => VtableParam(n.into_iter().map(f).collect()), - VtableBuiltin(i) => { - VtableBuiltin(VtableBuiltinData { nested: i.nested.into_iter().map(f).collect() }) - } - VtableObject(o) => VtableObject(VtableObjectData { - upcast_trait_ref: o.upcast_trait_ref, - vtable_base: o.vtable_base, - nested: o.nested.into_iter().map(f).collect(), - }), - VtableAutoImpl(d) => VtableAutoImpl(VtableAutoImplData { - trait_def_id: d.trait_def_id, - nested: d.nested.into_iter().map(f).collect(), - }), - VtableClosure(c) => VtableClosure(VtableClosureData { - closure_def_id: c.closure_def_id, - substs: c.substs, - nested: c.nested.into_iter().map(f).collect(), - }), - VtableGenerator(c) => VtableGenerator(VtableGeneratorData { - generator_def_id: c.generator_def_id, - substs: c.substs, - nested: c.nested.into_iter().map(f).collect(), - }), - VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData { - fn_ty: p.fn_ty, - nested: p.nested.into_iter().map(f).collect(), - }), - VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData { - alias_def_id: d.alias_def_id, - substs: d.substs, - nested: d.nested.into_iter().map(f).collect(), - }), - } - } -} - -/// Identifies a particular impl in the source, along with a set of -/// substitutions from the impl's type/lifetime parameters. The -/// `nested` vector corresponds to the nested obligations attached to -/// the impl's type parameters. -/// -/// The type parameter `N` indicates the type used for "nested -/// obligations" that are required by the impl. During type-check, this -/// is `Obligation`, as one might expect. During codegen, however, this -/// is `()`, because codegen only requires a shallow resolution of an -/// impl, and nested obligations are satisfied later. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableImplData<'tcx, N> { - pub impl_def_id: DefId, - pub substs: SubstsRef<'tcx>, - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableGeneratorData<'tcx, N> { - pub generator_def_id: DefId, - pub substs: SubstsRef<'tcx>, - /// Nested obligations. This can be non-empty if the generator - /// signature contains associated types. - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableClosureData<'tcx, N> { - pub closure_def_id: DefId, - pub substs: SubstsRef<'tcx>, - /// Nested obligations. This can be non-empty if the closure - /// signature contains associated types. - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableAutoImplData<N> { - pub trait_def_id: DefId, - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableBuiltinData<N> { - pub nested: Vec<N>, -} - -/// A vtable for some object-safe trait `Foo` automatically derived -/// for the object type `Foo`. -#[derive(PartialEq, Eq, Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableObjectData<'tcx, N> { - /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. - pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, - - /// The vtable is formed by concatenating together the method lists of - /// the base object trait and all supertraits; this is the start of - /// `upcast_trait_ref`'s methods in that vtable. - pub vtable_base: usize, - - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableFnPointerData<'tcx, N> { - pub fn_ty: Ty<'tcx>, - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableTraitAliasData<'tcx, N> { - pub alias_def_id: DefId, - pub substs: SubstsRef<'tcx>, - pub nested: Vec<N>, -} - -pub trait ExClauseFold<'tcx> -where - Self: chalk_engine::context::Context + Clone, -{ - fn fold_ex_clause_with<F: TypeFolder<'tcx>>( - ex_clause: &chalk_engine::ExClause<Self>, - folder: &mut F, - ) -> chalk_engine::ExClause<Self>; - - fn visit_ex_clause_with<V: TypeVisitor<'tcx>>( - ex_clause: &chalk_engine::ExClause<Self>, - visitor: &mut V, - ) -> bool; -} - -pub trait ChalkContextLift<'tcx> -where - Self: chalk_engine::context::Context + Clone, -{ - type LiftedExClause: Debug + 'tcx; - type LiftedDelayedLiteral: Debug + 'tcx; - type LiftedLiteral: Debug + 'tcx; - - fn lift_ex_clause_to_tcx( - ex_clause: &chalk_engine::ExClause<Self>, - tcx: TyCtxt<'tcx>, - ) -> Option<Self::LiftedExClause>; - - fn lift_delayed_literal_to_tcx( - ex_clause: &chalk_engine::DelayedLiteral<Self>, - tcx: TyCtxt<'tcx>, - ) -> Option<Self::LiftedDelayedLiteral>; - - fn lift_literal_to_tcx( - ex_clause: &chalk_engine::Literal<Self>, - tcx: TyCtxt<'tcx>, - ) -> Option<Self::LiftedLiteral>; -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)] -pub enum ObjectSafetyViolation { - /// `Self: Sized` declared on the trait. - SizedSelf(SmallVec<[Span; 1]>), - - /// Supertrait reference references `Self` an in illegal location - /// (e.g., `trait Foo : Bar<Self>`). - SupertraitSelf(SmallVec<[Span; 1]>), - - /// Method has something illegal. - Method(ast::Name, MethodViolationCode, Span), - - /// Associated const. - AssocConst(ast::Name, Span), -} - -impl ObjectSafetyViolation { - pub fn error_msg(&self) -> Cow<'static, str> { - match *self { - ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), - ObjectSafetyViolation::SupertraitSelf(ref spans) => { - if spans.iter().any(|sp| *sp != DUMMY_SP) { - "it uses `Self` as a type parameter in this".into() - } else { - "it cannot use `Self` as a type parameter in a supertrait or `where`-clause" - .into() - } - } - ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { - format!("associated function `{}` has no `self` parameter", name).into() - } - ObjectSafetyViolation::Method( - name, - MethodViolationCode::ReferencesSelfInput(_), - DUMMY_SP, - ) => format!("method `{}` references the `Self` type in its parameters", name).into(), - ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfInput(_), _) => { - format!("method `{}` references the `Self` type in this parameter", name).into() - } - ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => { - format!("method `{}` references the `Self` type in its return type", name).into() - } - ObjectSafetyViolation::Method( - name, - MethodViolationCode::WhereClauseReferencesSelf, - _, - ) => { - format!("method `{}` references the `Self` type in its `where` clause", name).into() - } - ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => { - format!("method `{}` has generic type parameters", name).into() - } - ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => { - format!("method `{}`'s `self` parameter cannot be dispatched on", name).into() - } - ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => { - format!("it contains associated `const` `{}`", name).into() - } - ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(), - } - } - - pub fn solution(&self) -> Option<(String, Option<(String, Span)>)> { - Some(match *self { - ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => { - return None; - } - ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(sugg), _) => ( - format!( - "consider turning `{}` into a method by giving it a `&self` argument or \ - constraining it so it does not apply to trait objects", - name - ), - sugg.map(|(sugg, sp)| (sugg.to_string(), sp)), - ), - ObjectSafetyViolation::Method( - name, - MethodViolationCode::UndispatchableReceiver, - span, - ) => ( - format!("consider changing method `{}`'s `self` parameter to be `&self`", name) - .into(), - Some(("&Self".to_string(), span)), - ), - ObjectSafetyViolation::AssocConst(name, _) - | ObjectSafetyViolation::Method(name, ..) => { - (format!("consider moving `{}` to another trait", name), None) - } - }) - } - - pub fn spans(&self) -> SmallVec<[Span; 1]> { - // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so - // diagnostics use a `note` instead of a `span_label`. - match self { - ObjectSafetyViolation::SupertraitSelf(spans) - | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(), - ObjectSafetyViolation::AssocConst(_, span) - | ObjectSafetyViolation::Method(_, _, span) - if *span != DUMMY_SP => - { - smallvec![*span] - } - _ => smallvec![], - } - } -} - -/// Reasons a method might not be object-safe. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] -pub enum MethodViolationCode { - /// e.g., `fn foo()` - StaticMethod(Option<(&'static str, Span)>), - - /// e.g., `fn foo(&self, x: Self)` - ReferencesSelfInput(usize), - - /// e.g., `fn foo(&self) -> Self` - ReferencesSelfOutput, - - /// e.g., `fn foo(&self) where Self: Clone` - WhereClauseReferencesSelf, - - /// e.g., `fn foo<A>()` - Generic, - - /// the method's receiver (`self` argument) can't be dispatched on - UndispatchableReceiver, -} diff --git a/src/librustc/traits/query.rs b/src/librustc/traits/query.rs deleted file mode 100644 index c9055182620..00000000000 --- a/src/librustc/traits/query.rs +++ /dev/null @@ -1,332 +0,0 @@ -//! Experimental types for the trait query interface. The methods -//! defined in this module are all based on **canonicalization**, -//! which makes a canonical query by replacing unbound inference -//! variables and regions, so that results can be reused more broadly. -//! The providers for the queries defined here can be found in -//! `librustc_traits`. - -use crate::ich::StableHashingContext; -use crate::infer::canonical::{Canonical, QueryResponse}; -use crate::ty::error::TypeError; -use crate::ty::subst::GenericArg; -use crate::ty::{self, Ty, TyCtxt}; - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::Lrc; -use rustc_errors::struct_span_err; -use rustc_span::source_map::Span; -use std::iter::FromIterator; -use std::mem; - -pub mod type_op { - use crate::ty::fold::TypeFoldable; - use crate::ty::subst::UserSubsts; - use crate::ty::{Predicate, Ty}; - use rustc_hir::def_id::DefId; - use std::fmt; - - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] - pub struct AscribeUserType<'tcx> { - pub mir_ty: Ty<'tcx>, - pub def_id: DefId, - pub user_substs: UserSubsts<'tcx>, - } - - impl<'tcx> AscribeUserType<'tcx> { - pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self { - Self { mir_ty, def_id, user_substs } - } - } - - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] - pub struct Eq<'tcx> { - pub a: Ty<'tcx>, - pub b: Ty<'tcx>, - } - - impl<'tcx> Eq<'tcx> { - pub fn new(a: Ty<'tcx>, b: Ty<'tcx>) -> Self { - Self { a, b } - } - } - - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] - pub struct Subtype<'tcx> { - pub sub: Ty<'tcx>, - pub sup: Ty<'tcx>, - } - - impl<'tcx> Subtype<'tcx> { - pub fn new(sub: Ty<'tcx>, sup: Ty<'tcx>) -> Self { - Self { sub, sup } - } - } - - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] - pub struct ProvePredicate<'tcx> { - pub predicate: Predicate<'tcx>, - } - - impl<'tcx> ProvePredicate<'tcx> { - pub fn new(predicate: Predicate<'tcx>) -> Self { - ProvePredicate { predicate } - } - } - - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] - pub struct Normalize<T> { - pub value: T, - } - - impl<'tcx, T> Normalize<T> - where - T: fmt::Debug + TypeFoldable<'tcx>, - { - pub fn new(value: T) -> Self { - Self { value } - } - } -} - -pub type CanonicalProjectionGoal<'tcx> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>; - -pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; - -pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; - -pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>; - -pub type CanonicalTypeOpEqGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Eq<'tcx>>>; - -pub type CanonicalTypeOpSubtypeGoal<'tcx> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Subtype<'tcx>>>; - -pub type CanonicalTypeOpProvePredicateGoal<'tcx> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ProvePredicate<'tcx>>>; - -pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>; - -#[derive(Clone, Debug, HashStable)] -pub struct NoSolution; - -pub type Fallible<T> = Result<T, NoSolution>; - -impl<'tcx> From<TypeError<'tcx>> for NoSolution { - fn from(_: TypeError<'tcx>) -> NoSolution { - NoSolution - } -} - -#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)] -pub struct DropckOutlivesResult<'tcx> { - pub kinds: Vec<GenericArg<'tcx>>, - pub overflows: Vec<Ty<'tcx>>, -} - -impl<'tcx> DropckOutlivesResult<'tcx> { - pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { - if let Some(overflow_ty) = self.overflows.iter().next() { - let mut err = struct_span_err!( - tcx.sess, - span, - E0320, - "overflow while adding drop-check rules for {}", - ty, - ); - err.note(&format!("overflowed on {}", overflow_ty)); - err.emit(); - } - } - - pub fn into_kinds_reporting_overflows( - self, - tcx: TyCtxt<'tcx>, - span: Span, - ty: Ty<'tcx>, - ) -> Vec<GenericArg<'tcx>> { - self.report_overflows(tcx, span, ty); - let DropckOutlivesResult { kinds, overflows: _ } = self; - kinds - } -} - -/// A set of constraints that need to be satisfied in order for -/// a type to be valid for destruction. -#[derive(Clone, Debug, HashStable)] -pub struct DtorckConstraint<'tcx> { - /// Types that are required to be alive in order for this - /// type to be valid for destruction. - pub outlives: Vec<ty::subst::GenericArg<'tcx>>, - - /// Types that could not be resolved: projections and params. - pub dtorck_types: Vec<Ty<'tcx>>, - - /// If, during the computation of the dtorck constraint, we - /// overflow, that gets recorded here. The caller is expected to - /// report an error. - pub overflows: Vec<Ty<'tcx>>, -} - -impl<'tcx> DtorckConstraint<'tcx> { - pub fn empty() -> DtorckConstraint<'tcx> { - DtorckConstraint { outlives: vec![], dtorck_types: vec![], overflows: vec![] } - } -} - -impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> { - fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self { - let mut result = Self::empty(); - - for DtorckConstraint { outlives, dtorck_types, overflows } in iter { - result.outlives.extend(outlives); - result.dtorck_types.extend(dtorck_types); - result.overflows.extend(overflows); - } - - result - } -} - -/// This returns true if the type `ty` is "trivial" for -/// dropck-outlives -- that is, if it doesn't require any types to -/// outlive. This is similar but not *quite* the same as the -/// `needs_drop` test in the compiler already -- that is, for every -/// type T for which this function return true, needs-drop would -/// return `false`. But the reverse does not hold: in particular, -/// `needs_drop` returns false for `PhantomData`, but it is not -/// trivial for dropck-outlives. -/// -/// Note also that `needs_drop` requires a "global" type (i.e., one -/// with erased regions), but this function does not. -pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind { - // None of these types have a destructor and hence they do not - // require anything in particular to outlive the dtor's - // execution. - ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - | ty::Bool - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Never - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Char - | ty::GeneratorWitness(..) - | ty::RawPtr(_) - | ty::Ref(..) - | ty::Str - | ty::Foreign(..) - | ty::Error => true, - - // [T; N] and [T] have same properties as T. - ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), - - // (T1..Tn) and closures have same properties as T1..Tn -- - // check if *any* of those are trivial. - ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), - ty::Closure(def_id, ref substs) => { - substs.as_closure().upvar_tys(def_id, tcx).all(|t| trivial_dropck_outlives(tcx, t)) - } - - ty::Adt(def, _) => { - if Some(def.did) == tcx.lang_items().manually_drop() { - // `ManuallyDrop` never has a dtor. - true - } else { - // Other types might. Moreover, PhantomData doesn't - // have a dtor, but it is considered to own its - // content, so it is non-trivial. Unions can have `impl Drop`, - // and hence are non-trivial as well. - false - } - } - - // The following *might* require a destructor: needs deeper inspection. - ty::Dynamic(..) - | ty::Projection(..) - | ty::Param(_) - | ty::Opaque(..) - | ty::Placeholder(..) - | ty::Infer(_) - | ty::Bound(..) - | ty::Generator(..) => false, - - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - } -} - -#[derive(Debug, HashStable)] -pub struct CandidateStep<'tcx> { - pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, - pub autoderefs: usize, - /// `true` if the type results from a dereference of a raw pointer. - /// when assembling candidates, we include these steps, but not when - /// picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods - /// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then - /// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't. - pub from_unsafe_deref: bool, - pub unsize: bool, -} - -#[derive(Clone, Debug, HashStable)] -pub struct MethodAutoderefStepsResult<'tcx> { - /// The valid autoderef steps that could be find. - pub steps: Lrc<Vec<CandidateStep<'tcx>>>, - /// If Some(T), a type autoderef reported an error on. - pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>, - /// If `true`, `steps` has been truncated due to reaching the - /// recursion limit. - pub reached_recursion_limit: bool, -} - -#[derive(Debug, HashStable)] -pub struct MethodAutoderefBadTy<'tcx> { - pub reached_raw_pointer: bool, - pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, -} - -/// Result from the `normalize_projection_ty` query. -#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] -pub struct NormalizationResult<'tcx> { - /// Result of normalization. - pub normalized_ty: Ty<'tcx>, -} - -/// Outlives bounds are relationships between generic parameters, -/// whether they both be regions (`'a: 'b`) or whether types are -/// involved (`T: 'a`). These relationships can be extracted from the -/// full set of predicates we understand or also from types (in which -/// case they are called implied bounds). They are fed to the -/// `OutlivesEnv` which in turn is supplied to the region checker and -/// other parts of the inference system. -#[derive(Clone, Debug, TypeFoldable, Lift)] -pub enum OutlivesBound<'tcx> { - RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), - RegionSubParam(ty::Region<'tcx>, ty::ParamTy), - RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OutlivesBound<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - OutlivesBound::RegionSubRegion(ref a, ref b) => { - a.hash_stable(hcx, hasher); - b.hash_stable(hcx, hasher); - } - OutlivesBound::RegionSubParam(ref a, ref b) => { - a.hash_stable(hcx, hasher); - b.hash_stable(hcx, hasher); - } - OutlivesBound::RegionSubProjection(ref a, ref b) => { - a.hash_stable(hcx, hasher); - b.hash_stable(hcx, hasher); - } - } - } -} diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs deleted file mode 100644 index ac3d0049c0c..00000000000 --- a/src/librustc/traits/select.rs +++ /dev/null @@ -1,290 +0,0 @@ -//! Candidate selection. See the [rustc guide] for more information on how this works. -//! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html#selection - -use self::EvaluationResult::*; - -use super::{SelectionError, SelectionResult}; - -use crate::dep_graph::DepNodeIndex; -use crate::ty::{self, TyCtxt}; - -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::Lock; -use rustc_hir::def_id::DefId; - -#[derive(Clone, Default)] -pub struct SelectionCache<'tcx> { - pub hashmap: Lock< - FxHashMap< - ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>, - WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>, - >, - >, -} - -impl<'tcx> SelectionCache<'tcx> { - /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear` - pub fn clear(&self) { - *self.hashmap.borrow_mut() = Default::default(); - } -} - -/// The selection process begins by considering all impls, where -/// clauses, and so forth that might resolve an obligation. Sometimes -/// we'll be able to say definitively that (e.g.) an impl does not -/// apply to the obligation: perhaps it is defined for `usize` but the -/// obligation is for `int`. In that case, we drop the impl out of the -/// list. But the other cases are considered *candidates*. -/// -/// For selection to succeed, there must be exactly one matching -/// candidate. If the obligation is fully known, this is guaranteed -/// by coherence. However, if the obligation contains type parameters -/// or variables, there may be multiple such impls. -/// -/// It is not a real problem if multiple matching impls exist because -/// of type variables - it just means the obligation isn't sufficiently -/// elaborated. In that case we report an ambiguity, and the caller can -/// try again after more type information has been gathered or report a -/// "type annotations needed" error. -/// -/// However, with type parameters, this can be a real problem - type -/// parameters don't unify with regular types, but they *can* unify -/// with variables from blanket impls, and (unless we know its bounds -/// will always be satisfied) picking the blanket impl will be wrong -/// for at least *some* substitutions. To make this concrete, if we have -/// -/// trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; } -/// impl<T: fmt::Debug> AsDebug for T { -/// type Out = T; -/// fn debug(self) -> fmt::Debug { self } -/// } -/// fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); } -/// -/// we can't just use the impl to resolve the `<T as AsDebug>` obligation -/// -- a type from another crate (that doesn't implement `fmt::Debug`) could -/// implement `AsDebug`. -/// -/// Because where-clauses match the type exactly, multiple clauses can -/// only match if there are unresolved variables, and we can mostly just -/// report this ambiguity in that case. This is still a problem - we can't -/// *do anything* with ambiguities that involve only regions. This is issue -/// #21974. -/// -/// If a single where-clause matches and there are no inference -/// variables left, then it definitely matches and we can just select -/// it. -/// -/// In fact, we even select the where-clause when the obligation contains -/// inference variables. The can lead to inference making "leaps of logic", -/// for example in this situation: -/// -/// pub trait Foo<T> { fn foo(&self) -> T; } -/// impl<T> Foo<()> for T { fn foo(&self) { } } -/// impl Foo<bool> for bool { fn foo(&self) -> bool { *self } } -/// -/// pub fn foo<T>(t: T) where T: Foo<bool> { -/// println!("{:?}", <T as Foo<_>>::foo(&t)); -/// } -/// fn main() { foo(false); } -/// -/// Here the obligation `<T as Foo<$0>>` can be matched by both the blanket -/// impl and the where-clause. We select the where-clause and unify `$0=bool`, -/// so the program prints "false". However, if the where-clause is omitted, -/// the blanket impl is selected, we unify `$0=()`, and the program prints -/// "()". -/// -/// Exactly the same issues apply to projection and object candidates, except -/// that we can have both a projection candidate and a where-clause candidate -/// for the same obligation. In that case either would do (except that -/// different "leaps of logic" would occur if inference variables are -/// present), and we just pick the where-clause. This is, for example, -/// required for associated types to work in default impls, as the bounds -/// are visible both as projection bounds and as where-clauses from the -/// parameter environment. -#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable)] -pub enum SelectionCandidate<'tcx> { - BuiltinCandidate { - /// `false` if there are no *further* obligations. - has_nested: bool, - }, - ParamCandidate(ty::PolyTraitRef<'tcx>), - ImplCandidate(DefId), - AutoImplCandidate(DefId), - - /// This is a trait matching with a projected type as `Self`, and - /// we found an applicable bound in the trait definition. - ProjectionCandidate, - - /// Implementation of a `Fn`-family trait by one of the anonymous types - /// generated for a `||` expression. - ClosureCandidate, - - /// Implementation of a `Generator` trait by one of the anonymous types - /// generated for a generator. - GeneratorCandidate, - - /// Implementation of a `Fn`-family trait by one of the anonymous - /// types generated for a fn pointer type (e.g., `fn(int) -> int`) - FnPointerCandidate, - - TraitAliasCandidate(DefId), - - ObjectCandidate, - - BuiltinObjectCandidate, - - BuiltinUnsizeCandidate, -} - -/// The result of trait evaluation. The order is important -/// here as the evaluation of a list is the maximum of the -/// evaluations. -/// -/// The evaluation results are ordered: -/// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions` -/// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown` -/// - `EvaluatedToErr` implies `EvaluatedToRecur` -/// - the "union" of evaluation results is equal to their maximum - -/// all the "potential success" candidates can potentially succeed, -/// so they are noops when unioned with a definite error, and within -/// the categories it's easy to see that the unions are correct. -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)] -pub enum EvaluationResult { - /// Evaluation successful. - EvaluatedToOk, - /// Evaluation successful, but there were unevaluated region obligations. - EvaluatedToOkModuloRegions, - /// Evaluation is known to be ambiguous -- it *might* hold for some - /// assignment of inference variables, but it might not. - /// - /// While this has the same meaning as `EvaluatedToUnknown` -- we can't - /// know whether this obligation holds or not -- it is the result we - /// would get with an empty stack, and therefore is cacheable. - EvaluatedToAmbig, - /// Evaluation failed because of recursion involving inference - /// variables. We are somewhat imprecise there, so we don't actually - /// know the real result. - /// - /// This can't be trivially cached for the same reason as `EvaluatedToRecur`. - EvaluatedToUnknown, - /// Evaluation failed because we encountered an obligation we are already - /// trying to prove on this branch. - /// - /// We know this branch can't be a part of a minimal proof-tree for - /// the "root" of our cycle, because then we could cut out the recursion - /// and maintain a valid proof tree. However, this does not mean - /// that all the obligations on this branch do not hold -- it's possible - /// that we entered this branch "speculatively", and that there - /// might be some other way to prove this obligation that does not - /// go through this cycle -- so we can't cache this as a failure. - /// - /// For example, suppose we have this: - /// - /// ```rust,ignore (pseudo-Rust) - /// pub trait Trait { fn xyz(); } - /// // This impl is "useless", but we can still have - /// // an `impl Trait for SomeUnsizedType` somewhere. - /// impl<T: Trait + Sized> Trait for T { fn xyz() {} } - /// - /// pub fn foo<T: Trait + ?Sized>() { - /// <T as Trait>::xyz(); - /// } - /// ``` - /// - /// When checking `foo`, we have to prove `T: Trait`. This basically - /// translates into this: - /// - /// ```plain,ignore - /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait - /// ``` - /// - /// When we try to prove it, we first go the first option, which - /// recurses. This shows us that the impl is "useless" -- it won't - /// tell us that `T: Trait` unless it already implemented `Trait` - /// by some other means. However, that does not prevent `T: Trait` - /// does not hold, because of the bound (which can indeed be satisfied - /// by `SomeUnsizedType` from another crate). - // - // FIXME: when an `EvaluatedToRecur` goes past its parent root, we - // ought to convert it to an `EvaluatedToErr`, because we know - // there definitely isn't a proof tree for that obligation. Not - // doing so is still sound -- there isn't any proof tree, so the - // branch still can't be a part of a minimal one -- but does not re-enable caching. - EvaluatedToRecur, - /// Evaluation failed. - EvaluatedToErr, -} - -impl EvaluationResult { - /// Returns `true` if this evaluation result is known to apply, even - /// considering outlives constraints. - pub fn must_apply_considering_regions(self) -> bool { - self == EvaluatedToOk - } - - /// Returns `true` if this evaluation result is known to apply, ignoring - /// outlives constraints. - pub fn must_apply_modulo_regions(self) -> bool { - self <= EvaluatedToOkModuloRegions - } - - pub fn may_apply(self) -> bool { - match self { - EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => { - true - } - - EvaluatedToErr | EvaluatedToRecur => false, - } - } - - pub fn is_stack_dependent(self) -> bool { - match self { - EvaluatedToUnknown | EvaluatedToRecur => true, - - EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false, - } - } -} - -/// Indicates that trait evaluation caused overflow. -#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)] -pub struct OverflowError; - -impl<'tcx> From<OverflowError> for SelectionError<'tcx> { - fn from(OverflowError: OverflowError) -> SelectionError<'tcx> { - SelectionError::Overflow - } -} - -#[derive(Clone, Default)] -pub struct EvaluationCache<'tcx> { - pub hashmap: Lock< - FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>, - >, -} - -impl<'tcx> EvaluationCache<'tcx> { - /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear` - pub fn clear(&self) { - *self.hashmap.borrow_mut() = Default::default(); - } -} - -#[derive(Clone, Eq, PartialEq)] -pub struct WithDepNode<T> { - dep_node: DepNodeIndex, - cached_value: T, -} - -impl<T: Clone> WithDepNode<T> { - pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self { - WithDepNode { dep_node, cached_value } - } - - pub fn get(&self, tcx: TyCtxt<'_>) -> T { - tcx.dep_graph.read_index(self.dep_node); - self.cached_value.clone() - } -} diff --git a/src/librustc/traits/specialization_graph.rs b/src/librustc/traits/specialization_graph.rs deleted file mode 100644 index ee813bf606e..00000000000 --- a/src/librustc/traits/specialization_graph.rs +++ /dev/null @@ -1,202 +0,0 @@ -use crate::ich::{self, StableHashingContext}; -use crate::ty::fast_reject::SimplifiedType; -use crate::ty::{self, TyCtxt}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::def_id::{DefId, DefIdMap}; -use syntax::ast::Ident; - -/// A per-trait graph of impls in specialization order. At the moment, this -/// graph forms a tree rooted with the trait itself, with all other nodes -/// representing impls, and parent-child relationships representing -/// specializations. -/// -/// The graph provides two key services: -/// -/// - Construction. This implicitly checks for overlapping impls (i.e., impls -/// that overlap but where neither specializes the other -- an artifact of the -/// simple "chain" rule. -/// -/// - Parent extraction. In particular, the graph can give you the *immediate* -/// parents of a given specializing impl, which is needed for extracting -/// default items amongst other things. In the simple "chain" rule, every impl -/// has at most one parent. -#[derive(RustcEncodable, RustcDecodable, HashStable)] -pub struct Graph { - // All impls have a parent; the "root" impls have as their parent the `def_id` - // of the trait. - pub parent: DefIdMap<DefId>, - - // The "root" impls are found by looking up the trait's def_id. - pub children: DefIdMap<Children>, -} - -impl Graph { - pub fn new() -> Graph { - Graph { parent: Default::default(), children: Default::default() } - } - - /// The parent of a given impl, which is the `DefId` of the trait when the - /// impl is a "specialization root". - pub fn parent(&self, child: DefId) -> DefId { - *self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child)) - } -} - -/// Children of a given impl, grouped into blanket/non-blanket varieties as is -/// done in `TraitDef`. -#[derive(Default, RustcEncodable, RustcDecodable)] -pub struct Children { - // Impls of a trait (or specializations of a given impl). To allow for - // quicker lookup, the impls are indexed by a simplified version of their - // `Self` type: impls with a simplifiable `Self` are stored in - // `nonblanket_impls` keyed by it, while all other impls are stored in - // `blanket_impls`. - // - // A similar division is used within `TraitDef`, but the lists there collect - // together *all* the impls for a trait, and are populated prior to building - // the specialization graph. - /// Impls of the trait. - pub nonblanket_impls: FxHashMap<SimplifiedType, Vec<DefId>>, - - /// Blanket impls associated with the trait. - pub blanket_impls: Vec<DefId>, -} - -/// A node in the specialization graph is either an impl or a trait -/// definition; either can serve as a source of item definitions. -/// There is always exactly one trait definition node: the root. -#[derive(Debug, Copy, Clone)] -pub enum Node { - Impl(DefId), - Trait(DefId), -} - -impl<'tcx> Node { - pub fn is_from_trait(&self) -> bool { - match *self { - Node::Trait(..) => true, - _ => false, - } - } - - /// Iterate over the items defined directly by the given (impl or trait) node. - pub fn items(&self, tcx: TyCtxt<'tcx>) -> impl 'tcx + Iterator<Item = &'tcx ty::AssocItem> { - tcx.associated_items(self.def_id()).in_definition_order() - } - - /// Finds an associated item defined in this node. - /// - /// If this returns `None`, the item can potentially still be found in - /// parents of this node. - pub fn item( - &self, - tcx: TyCtxt<'tcx>, - trait_item_name: Ident, - trait_item_kind: ty::AssocKind, - trait_def_id: DefId, - ) -> Option<ty::AssocItem> { - use crate::ty::AssocKind::*; - - tcx.associated_items(self.def_id()) - .filter_by_name_unhygienic(trait_item_name.name) - .find(move |impl_item| { - match (trait_item_kind, impl_item.kind) { - | (Const, Const) - | (Method, Method) - | (Type, Type) - | (Type, OpaqueTy) // assoc. types can be made opaque in impls - => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id), - - | (Const, _) - | (Method, _) - | (Type, _) - | (OpaqueTy, _) - => false, - } - }) - .copied() - } - - pub fn def_id(&self) -> DefId { - match *self { - Node::Impl(did) => did, - Node::Trait(did) => did, - } - } -} - -#[derive(Copy, Clone)] -pub struct Ancestors<'tcx> { - trait_def_id: DefId, - specialization_graph: &'tcx Graph, - current_source: Option<Node>, -} - -impl Iterator for Ancestors<'_> { - type Item = Node; - fn next(&mut self) -> Option<Node> { - let cur = self.current_source.take(); - if let Some(Node::Impl(cur_impl)) = cur { - let parent = self.specialization_graph.parent(cur_impl); - - self.current_source = if parent == self.trait_def_id { - Some(Node::Trait(parent)) - } else { - Some(Node::Impl(parent)) - }; - } - cur - } -} - -pub struct NodeItem<T> { - pub node: Node, - pub item: T, -} - -impl<T> NodeItem<T> { - pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> { - NodeItem { node: self.node, item: f(self.item) } - } -} - -impl<'tcx> Ancestors<'tcx> { - /// Finds the bottom-most (ie. most specialized) definition of an associated - /// item. - pub fn leaf_def( - mut self, - tcx: TyCtxt<'tcx>, - trait_item_name: Ident, - trait_item_kind: ty::AssocKind, - ) -> Option<NodeItem<ty::AssocItem>> { - let trait_def_id = self.trait_def_id; - self.find_map(|node| { - node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) - .map(|item| NodeItem { node, item }) - }) - } -} - -/// Walk up the specialization ancestors of a given impl, starting with that -/// impl itself. -pub fn ancestors( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - start_from_impl: DefId, -) -> Ancestors<'tcx> { - let specialization_graph = tcx.specialization_graph_of(trait_def_id); - Ancestors { - trait_def_id, - specialization_graph, - current_source: Some(Node::Impl(start_from_impl)), - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for Children { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let Children { ref nonblanket_impls, ref blanket_impls } = *self; - - ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls); - } -} diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs deleted file mode 100644 index 48ed29f2bb3..00000000000 --- a/src/librustc/traits/structural_impls.rs +++ /dev/null @@ -1,712 +0,0 @@ -use crate::traits; -use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use crate::ty::{self, Lift, Ty, TyCtxt}; -use rustc_span::symbol::Symbol; -use smallvec::SmallVec; - -use std::collections::{BTreeMap, BTreeSet}; -use std::fmt; -use std::rc::Rc; - -// Structural impls for the structs in `traits`. - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - super::VtableImpl(ref v) => write!(f, "{:?}", v), - - super::VtableAutoImpl(ref t) => write!(f, "{:?}", t), - - super::VtableClosure(ref d) => write!(f, "{:?}", d), - - super::VtableGenerator(ref d) => write!(f, "{:?}", d), - - super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d), - - super::VtableObject(ref d) => write!(f, "{:?}", d), - - super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n), - - super::VtableBuiltin(ref d) => write!(f, "{:?}", d), - - super::VtableTraitAlias(ref d) => write!(f, "{:?}", d), - } - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableImplData(impl_def_id={:?}, substs={:?}, nested={:?})", - self.impl_def_id, self.substs, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})", - self.generator_def_id, self.substs, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableClosureData(closure_def_id={:?}, substs={:?}, nested={:?})", - self.closure_def_id, self.substs, self.nested - ) - } -} - -impl<N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "VtableBuiltinData(nested={:?})", self.nested) - } -} - -impl<N: fmt::Debug> fmt::Debug for traits::VtableAutoImplData<N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableAutoImplData(trait_def_id={:?}, nested={:?})", - self.trait_def_id, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})", - self.upcast_trait_ref, self.vtable_base, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "VtableFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})", - self.alias_def_id, self.substs, self.nested - ) - } -} - -impl<'tcx> fmt::Display for traits::WhereClause<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::WhereClause::*; - - // Bypass `ty::print` because it does not print out anonymous regions. - // FIXME(eddyb) implement a custom `PrettyPrinter`, or move this to `ty::print`. - fn write_region_name<'tcx>( - r: ty::Region<'tcx>, - fmt: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - match r { - ty::ReLateBound(index, br) => match br { - ty::BoundRegion::BrNamed(_, name) => write!(fmt, "{}", name), - ty::BoundRegion::BrAnon(var) => { - if *index == ty::INNERMOST { - write!(fmt, "'^{}", var) - } else { - write!(fmt, "'^{}_{}", index.index(), var) - } - } - _ => write!(fmt, "'_"), - }, - - _ => write!(fmt, "{}", r), - } - } - - match self { - Implemented(trait_ref) => write!(fmt, "Implemented({})", trait_ref), - ProjectionEq(projection) => write!(fmt, "ProjectionEq({})", projection), - RegionOutlives(predicate) => { - write!(fmt, "RegionOutlives({}: ", predicate.0)?; - write_region_name(predicate.1, fmt)?; - write!(fmt, ")") - } - TypeOutlives(predicate) => { - write!(fmt, "TypeOutlives({}: ", predicate.0)?; - write_region_name(predicate.1, fmt)?; - write!(fmt, ")") - } - } - } -} - -impl<'tcx> fmt::Display for traits::WellFormed<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::WellFormed::*; - - match self { - Trait(trait_ref) => write!(fmt, "WellFormed({})", trait_ref), - Ty(ty) => write!(fmt, "WellFormed({})", ty), - } - } -} - -impl<'tcx> fmt::Display for traits::FromEnv<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::FromEnv::*; - - match self { - Trait(trait_ref) => write!(fmt, "FromEnv({})", trait_ref), - Ty(ty) => write!(fmt, "FromEnv({})", ty), - } - } -} - -impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::DomainGoal::*; - - match self { - Holds(wc) => write!(fmt, "{}", wc), - WellFormed(wf) => write!(fmt, "{}", wf), - FromEnv(from_env) => write!(fmt, "{}", from_env), - Normalize(projection) => { - write!(fmt, "Normalize({} -> {})", projection.projection_ty, projection.ty) - } - } - } -} - -impl fmt::Display for traits::QuantifierKind { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::QuantifierKind::*; - - match self { - Universal => write!(fmt, "forall"), - Existential => write!(fmt, "exists"), - } - } -} - -/// Collect names for regions / types bound by a quantified goal / clause. -/// This collector does not try to do anything clever like in `ty::print`, it's just used -/// for debug output in tests anyway. -struct BoundNamesCollector { - // Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway. - regions: BTreeSet<Symbol>, - - // Sort by `BoundVar` index, so usually this should be equivalent to the order given - // by the list of type parameters. - types: BTreeMap<u32, Symbol>, - - binder_index: ty::DebruijnIndex, -} - -impl BoundNamesCollector { - fn new() -> Self { - BoundNamesCollector { - regions: BTreeSet::new(), - types: BTreeMap::new(), - binder_index: ty::INNERMOST, - } - } - - fn is_empty(&self) -> bool { - self.regions.is_empty() && self.types.is_empty() - } - - fn write_names(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut start = true; - for r in &self.regions { - if !start { - write!(fmt, ", ")?; - } - start = false; - write!(fmt, "{}", r)?; - } - for (_, t) in &self.types { - if !start { - write!(fmt, ", ")?; - } - start = false; - write!(fmt, "{}", t)?; - } - Ok(()) - } -} - -impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool { - self.binder_index.shift_in(1); - let result = t.super_visit_with(self); - self.binder_index.shift_out(1); - result - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.kind { - ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { - self.types.insert( - bound_ty.var.as_u32(), - match bound_ty.kind { - ty::BoundTyKind::Param(name) => name, - ty::BoundTyKind::Anon => { - Symbol::intern(&format!("^{}", bound_ty.var.as_u32())) - } - }, - ); - } - - _ => (), - }; - - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - match r { - ty::ReLateBound(index, br) if *index == self.binder_index => match br { - ty::BoundRegion::BrNamed(_, name) => { - self.regions.insert(*name); - } - - ty::BoundRegion::BrAnon(var) => { - self.regions.insert(Symbol::intern(&format!("'^{}", var))); - } - - _ => (), - }, - - _ => (), - }; - - r.super_visit_with(self) - } -} - -impl<'tcx> fmt::Display for traits::Goal<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::GoalKind::*; - - match self { - Implies(hypotheses, goal) => { - write!(fmt, "if (")?; - for (index, hyp) in hypotheses.iter().enumerate() { - if index > 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{}", hyp)?; - } - write!(fmt, ") {{ {} }}", goal) - } - And(goal1, goal2) => write!(fmt, "({} && {})", goal1, goal2), - Not(goal) => write!(fmt, "not {{ {} }}", goal), - DomainGoal(goal) => write!(fmt, "{}", goal), - Quantified(qkind, goal) => { - let mut collector = BoundNamesCollector::new(); - goal.skip_binder().visit_with(&mut collector); - - if !collector.is_empty() { - write!(fmt, "{}<", qkind)?; - collector.write_names(fmt)?; - write!(fmt, "> {{ ")?; - } - - write!(fmt, "{}", goal.skip_binder())?; - - if !collector.is_empty() { - write!(fmt, " }}")?; - } - - Ok(()) - } - Subtype(a, b) => write!(fmt, "{} <: {}", a, b), - CannotProve => write!(fmt, "CannotProve"), - } - } -} - -impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let traits::ProgramClause { goal, hypotheses, .. } = self; - write!(fmt, "{}", goal)?; - if !hypotheses.is_empty() { - write!(fmt, " :- ")?; - for (index, condition) in hypotheses.iter().enumerate() { - if index > 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{}", condition)?; - } - } - write!(fmt, ".") - } -} - -impl<'tcx> fmt::Display for traits::Clause<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::Clause::*; - - match self { - Implies(clause) => write!(fmt, "{}", clause), - ForAll(clause) => { - let mut collector = BoundNamesCollector::new(); - clause.skip_binder().visit_with(&mut collector); - - if !collector.is_empty() { - write!(fmt, "forall<")?; - collector.write_names(fmt)?; - write!(fmt, "> {{ ")?; - } - - write!(fmt, "{}", clause.skip_binder())?; - - if !collector.is_empty() { - write!(fmt, " }}")?; - } - - Ok(()) - } - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Lift implementations - -impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> { - type Lifted = traits::SelectionError<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match *self { - super::Unimplemented => Some(super::Unimplemented), - super::OutputTypeParameterMismatch(a, b, ref err) => { - tcx.lift(&(a, b)).and_then(|(a, b)| { - tcx.lift(err).map(|err| super::OutputTypeParameterMismatch(a, b, err)) - }) - } - super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)), - super::ConstEvalFailure(err) => Some(super::ConstEvalFailure(err)), - super::Overflow => Some(super::Overflow), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { - type Lifted = traits::ObligationCauseCode<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match *self { - super::ReturnNoExpression => Some(super::ReturnNoExpression), - super::MiscObligation => Some(super::MiscObligation), - super::SliceOrArrayElem => Some(super::SliceOrArrayElem), - super::TupleElem => Some(super::TupleElem), - super::ProjectionWf(proj) => tcx.lift(&proj).map(super::ProjectionWf), - super::ItemObligation(def_id) => Some(super::ItemObligation(def_id)), - super::BindingObligation(def_id, span) => Some(super::BindingObligation(def_id, span)), - super::ReferenceOutlivesReferent(ty) => { - tcx.lift(&ty).map(super::ReferenceOutlivesReferent) - } - super::ObjectTypeBound(ty, r) => tcx - .lift(&ty) - .and_then(|ty| tcx.lift(&r).and_then(|r| Some(super::ObjectTypeBound(ty, r)))), - super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation), - super::Coercion { source, target } => { - Some(super::Coercion { source: tcx.lift(&source)?, target: tcx.lift(&target)? }) - } - super::AssignmentLhsSized => Some(super::AssignmentLhsSized), - super::TupleInitializerSized => Some(super::TupleInitializerSized), - super::StructInitializerSized => Some(super::StructInitializerSized), - super::VariableType(id) => Some(super::VariableType(id)), - super::ReturnValue(id) => Some(super::ReturnValue(id)), - super::ReturnType => Some(super::ReturnType), - super::SizedArgumentType => Some(super::SizedArgumentType), - super::SizedReturnType => Some(super::SizedReturnType), - super::SizedYieldType => Some(super::SizedYieldType), - super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)), - super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }), - super::ConstSized => Some(super::ConstSized), - super::ConstPatternStructural => Some(super::ConstPatternStructural), - super::SharedStatic => Some(super::SharedStatic), - super::BuiltinDerivedObligation(ref cause) => { - tcx.lift(cause).map(super::BuiltinDerivedObligation) - } - super::ImplDerivedObligation(ref cause) => { - tcx.lift(cause).map(super::ImplDerivedObligation) - } - super::CompareImplMethodObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - } => Some(super::CompareImplMethodObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - }), - super::CompareImplTypeObligation { item_name, impl_item_def_id, trait_item_def_id } => { - Some(super::CompareImplTypeObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - }) - } - super::ExprAssignable => Some(super::ExprAssignable), - super::MatchExpressionArm(box super::MatchExpressionArmCause { - arm_span, - source, - ref prior_arms, - last_ty, - scrut_hir_id, - }) => tcx.lift(&last_ty).map(|last_ty| { - super::MatchExpressionArm(box super::MatchExpressionArmCause { - arm_span, - source, - prior_arms: prior_arms.clone(), - last_ty, - scrut_hir_id, - }) - }), - super::Pattern { span, root_ty, origin_expr } => { - tcx.lift(&root_ty).map(|root_ty| super::Pattern { span, root_ty, origin_expr }) - } - super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => { - Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon })) - } - super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse), - super::MainFunctionType => Some(super::MainFunctionType), - super::StartFunctionType => Some(super::StartFunctionType), - super::IntrinsicType => Some(super::IntrinsicType), - super::MethodReceiver => Some(super::MethodReceiver), - super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)), - super::TrivialBound => Some(super::TrivialBound), - super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> { - type Lifted = traits::DerivedObligationCause<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| { - tcx.lift(&*self.parent_code).map(|code| traits::DerivedObligationCause { - parent_trait_ref: trait_ref, - parent_code: Rc::new(code), - }) - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> { - type Lifted = traits::ObligationCause<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.code).map(|code| traits::ObligationCause { - span: self.span, - body_id: self.body_id, - code, - }) - } -} - -// For codegen only. -impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { - type Lifted = traits::Vtable<'tcx, ()>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match self.clone() { - traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) => { - tcx.lift(&substs).map(|substs| { - traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) - }) - } - traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)), - traits::VtableGenerator(traits::VtableGeneratorData { - generator_def_id, - substs, - nested, - }) => tcx.lift(&substs).map(|substs| { - traits::VtableGenerator(traits::VtableGeneratorData { - generator_def_id: generator_def_id, - substs: substs, - nested: nested, - }) - }), - traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, nested }) => { - tcx.lift(&substs).map(|substs| { - traits::VtableClosure(traits::VtableClosureData { - closure_def_id, - substs, - nested, - }) - }) - } - traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => { - tcx.lift(&fn_ty).map(|fn_ty| { - traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) - }) - } - traits::VtableParam(n) => Some(traits::VtableParam(n)), - traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)), - traits::VtableObject(traits::VtableObjectData { - upcast_trait_ref, - vtable_base, - nested, - }) => tcx.lift(&upcast_trait_ref).map(|trait_ref| { - traits::VtableObject(traits::VtableObjectData { - upcast_trait_ref: trait_ref, - vtable_base, - nested, - }) - }), - traits::VtableTraitAlias(traits::VtableTraitAliasData { - alias_def_id, - substs, - nested, - }) => tcx.lift(&substs).map(|substs| { - traits::VtableTraitAlias(traits::VtableTraitAliasData { - alias_def_id, - substs, - nested, - }) - }), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for traits::Environment<'a> { - type Lifted = traits::Environment<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.clauses).map(|clauses| traits::Environment { clauses }) - } -} - -impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> { - type Lifted = traits::InEnvironment<'tcx, G::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.environment).and_then(|environment| { - tcx.lift(&self.goal).map(|goal| traits::InEnvironment { environment, goal }) - }) - } -} - -impl<'tcx, C> Lift<'tcx> for chalk_engine::ExClause<C> -where - C: chalk_engine::context::Context + Clone, - C: traits::ChalkContextLift<'tcx>, -{ - type Lifted = C::LiftedExClause; - - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - <C as traits::ChalkContextLift>::lift_ex_clause_to_tcx(self, tcx) - } -} - -impl<'tcx, C> Lift<'tcx> for chalk_engine::DelayedLiteral<C> -where - C: chalk_engine::context::Context + Clone, - C: traits::ChalkContextLift<'tcx>, -{ - type Lifted = C::LiftedDelayedLiteral; - - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - <C as traits::ChalkContextLift>::lift_delayed_literal_to_tcx(self, tcx) - } -} - -impl<'tcx, C> Lift<'tcx> for chalk_engine::Literal<C> -where - C: chalk_engine::context::Context + Clone, - C: traits::ChalkContextLift<'tcx>, -{ - type Lifted = C::LiftedLiteral; - - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - <C as traits::ChalkContextLift>::lift_literal_to_tcx(self, tcx) - } -} - -/////////////////////////////////////////////////////////////////////////// -// TypeFoldable implementations. - -CloneTypeFoldableAndLiftImpls! { - traits::QuantifierKind, -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<traits::Goal<'tcx>> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); - folder.tcx().intern_goals(&v) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let v = (**self).fold_with(folder); - folder.tcx().mk_goal(v) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - (**self).visit_with(visitor) - } -} - -CloneTypeFoldableAndLiftImpls! { - traits::ProgramClauseCategory, -} - -impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); - folder.tcx().intern_clauses(&v) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::ExClause<C> -where - C: traits::ExClauseFold<'tcx>, - C::Substitution: Clone, - C::RegionConstraint: Clone, -{ - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - <C as traits::ExClauseFold>::fold_ex_clause_with(self, folder) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - <C as traits::ExClauseFold>::visit_ex_clause_with(self, visitor) - } -} - -EnumTypeFoldableImpl! { - impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::DelayedLiteral<C> { - (chalk_engine::DelayedLiteral::CannotProve)(a), - (chalk_engine::DelayedLiteral::Negative)(a), - (chalk_engine::DelayedLiteral::Positive)(a, b), - } where - C: chalk_engine::context::Context<CanonicalConstrainedSubst: TypeFoldable<'tcx>> + Clone, -} - -EnumTypeFoldableImpl! { - impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::Literal<C> { - (chalk_engine::Literal::Negative)(a), - (chalk_engine::Literal::Positive)(a), - } where - C: chalk_engine::context::Context<GoalInEnvironment: Clone + TypeFoldable<'tcx>> + Clone, -} - -CloneTypeFoldableAndLiftImpls! { - chalk_engine::TableIndex, -} diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs deleted file mode 100644 index 35f8eb20475..00000000000 --- a/src/librustc/ty/_match.rs +++ /dev/null @@ -1,120 +0,0 @@ -use crate::ty::error::TypeError; -use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::ty::{self, InferConst, Ty, TyCtxt}; - -/// A type "A" *matches* "B" if the fresh types in B could be -/// substituted with values so as to make it equal to A. Matching is -/// intended to be used only on freshened types, and it basically -/// indicates if the non-freshened versions of A and B could have been -/// unified. -/// -/// It is only an approximation. If it yields false, unification would -/// definitely fail, but a true result doesn't mean unification would -/// succeed. This is because we don't track the "side-constraints" on -/// type variables, nor do we track if the same freshened type appears -/// more than once. To some extent these approximations could be -/// fixed, given effort. -/// -/// Like subtyping, matching is really a binary relation, so the only -/// important thing about the result is Ok/Err. Also, matching never -/// affects any type variables or unification state. -pub struct Match<'tcx> { - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, -} - -impl Match<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Match<'tcx> { - Match { tcx, param_env } - } -} - -impl TypeRelation<'tcx> for Match<'tcx> { - fn tag(&self) -> &'static str { - "Match" - } - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - fn a_is_expected(&self) -> bool { - true - } // irrelevant - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - _: ty::Variance, - a: &T, - b: &T, - ) -> RelateResult<'tcx, T> { - self.relate(a, b) - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("{}.regions({:?}, {:?})", self.tag(), a, b); - Ok(a) - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), a, b); - if a == b { - return Ok(a); - } - - match (&a.kind, &b.kind) { - (_, &ty::Infer(ty::FreshTy(_))) - | (_, &ty::Infer(ty::FreshIntTy(_))) - | (_, &ty::Infer(ty::FreshFloatTy(_))) => Ok(a), - - (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(relate::expected_found(self, &a, &b))) - } - - (&ty::Error, _) | (_, &ty::Error) => Ok(self.tcx().types.err), - - _ => relate::super_relate_tys(self, a, b), - } - } - - fn consts( - &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - debug!("{}.consts({:?}, {:?})", self.tag(), a, b); - if a == b { - return Ok(a); - } - - match (a.val, b.val) { - (_, ty::ConstKind::Infer(InferConst::Fresh(_))) => { - return Ok(a); - } - - (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { - return Err(TypeError::ConstMismatch(relate::expected_found(self, &a, &b))); - } - - _ => {} - } - - relate::super_relate_consts(self, a, b) - } - - fn binders<T>( - &mut self, - a: &ty::Binder<T>, - b: &ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> - where - T: Relate<'tcx>, - { - Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) - } -} diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs deleted file mode 100644 index 851bffc2065..00000000000 --- a/src/librustc/ty/adjustment.rs +++ /dev/null @@ -1,194 +0,0 @@ -use crate::ty::subst::SubstsRef; -use crate::ty::{self, Ty, TyCtxt}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_macros::HashStable; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] -pub enum PointerCast { - /// Go from a fn-item type to a fn-pointer type. - ReifyFnPointer, - - /// Go from a safe fn pointer to an unsafe fn pointer. - UnsafeFnPointer, - - /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer. - /// It cannot convert a closure that requires unsafe. - ClosureFnPointer(hir::Unsafety), - - /// Go from a mut raw pointer to a const raw pointer. - MutToConstPointer, - - /// Go from `*const [T; N]` to `*const T` - ArrayToPointer, - - /// Unsize a pointer/reference value, e.g., `&[T; n]` to - /// `&[T]`. Note that the source could be a thin or fat pointer. - /// This will do things like convert thin pointers to fat - /// pointers, or convert structs containing thin pointers to - /// structs containing fat pointers, or convert between fat - /// pointers. We don't store the details of how the transform is - /// done (in fact, we don't know that, because it might depend on - /// the precise type parameters). We just store the target - /// type. Codegen backends and miri figure out what has to be done - /// based on the precise source/target type at hand. - Unsize, -} - -/// Represents coercing a value to a different type of value. -/// -/// We transform values by following a number of `Adjust` steps in order. -/// See the documentation on variants of `Adjust` for more details. -/// -/// Here are some common scenarios: -/// -/// 1. The simplest cases are where a pointer is not adjusted fat vs thin. -/// Here the pointer will be dereferenced N times (where a dereference can -/// happen to raw or borrowed pointers or any smart pointer which implements -/// Deref, including Box<_>). The types of dereferences is given by -/// `autoderefs`. It can then be auto-referenced zero or one times, indicated -/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is -/// `false`. -/// -/// 2. A thin-to-fat coercion involves unsizing the underlying data. We start -/// with a thin pointer, deref a number of times, unsize the underlying data, -/// then autoref. The 'unsize' phase may change a fixed length array to a -/// dynamically sized one, a concrete object to a trait object, or statically -/// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is -/// represented by: -/// -/// ``` -/// Deref(None) -> [i32; 4], -/// Borrow(AutoBorrow::Ref) -> &[i32; 4], -/// Unsize -> &[i32], -/// ``` -/// -/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. -/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> -/// The autoderef and -ref are the same as in the above example, but the type -/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about -/// the underlying conversions from `[i32; 4]` to `[i32]`. -/// -/// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In -/// that case, we have the pointer we need coming in, so there are no -/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. -/// At some point, of course, `Box` should move out of the compiler, in which -/// case this is analogous to transforming a struct. E.g., Box<[i32; 4]> -> -/// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`. -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct Adjustment<'tcx> { - pub kind: Adjust<'tcx>, - pub target: Ty<'tcx>, -} - -impl Adjustment<'tcx> { - pub fn is_region_borrow(&self) -> bool { - match self.kind { - Adjust::Borrow(AutoBorrow::Ref(..)) => true, - _ => false, - } - } -} - -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub enum Adjust<'tcx> { - /// Go from ! to any type. - NeverToAny, - - /// Dereference once, producing a place. - Deref(Option<OverloadedDeref<'tcx>>), - - /// Take the address and produce either a `&` or `*` pointer. - Borrow(AutoBorrow<'tcx>), - - Pointer(PointerCast), -} - -/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` -/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`. -/// The target type is `U` in both cases, with the region and mutability -/// being those shared by both the receiver and the returned reference. -#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct OverloadedDeref<'tcx> { - pub region: ty::Region<'tcx>, - pub mutbl: hir::Mutability, -} - -impl<'tcx> OverloadedDeref<'tcx> { - pub fn method_call(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> (DefId, SubstsRef<'tcx>) { - let trait_def_id = match self.mutbl { - hir::Mutability::Not => tcx.lang_items().deref_trait(), - hir::Mutability::Mut => tcx.lang_items().deref_mut_trait(), - }; - let method_def_id = tcx - .associated_items(trait_def_id.unwrap()) - .in_definition_order() - .find(|m| m.kind == ty::AssocKind::Method) - .unwrap() - .def_id; - (method_def_id, tcx.mk_substs_trait(source, &[])) - } -} - -/// At least for initial deployment, we want to limit two-phase borrows to -/// only a few specific cases. Right now, those are mostly "things that desugar" -/// into method calls: -/// - using `x.some_method()` syntax, where some_method takes `&mut self`, -/// - using `Foo::some_method(&mut x, ...)` syntax, -/// - binary assignment operators (`+=`, `-=`, `*=`, etc.). -/// Anything else should be rejected until generalized two-phase borrow support -/// is implemented. Right now, dataflow can't handle the general case where there -/// is more than one use of a mutable borrow, and we don't want to accept too much -/// new code via two-phase borrows, so we try to limit where we create two-phase -/// capable mutable borrows. -/// See #49434 for tracking. -#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub enum AllowTwoPhase { - Yes, - No, -} - -#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub enum AutoBorrowMutability { - Mut { allow_two_phase_borrow: AllowTwoPhase }, - Not, -} - -impl From<AutoBorrowMutability> for hir::Mutability { - fn from(m: AutoBorrowMutability) -> Self { - match m { - AutoBorrowMutability::Mut { .. } => hir::Mutability::Mut, - AutoBorrowMutability::Not => hir::Mutability::Not, - } - } -} - -#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub enum AutoBorrow<'tcx> { - /// Converts from T to &T. - Ref(ty::Region<'tcx>, AutoBorrowMutability), - - /// Converts from T to *T. - RawPtr(hir::Mutability), -} - -/// Information for `CoerceUnsized` impls, storing information we -/// have computed about the coercion. -/// -/// This struct can be obtained via the `coerce_impl_info` query. -/// Demanding this struct also has the side-effect of reporting errors -/// for inappropriate impls. -#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, HashStable)] -pub struct CoerceUnsizedInfo { - /// If this is a "custom coerce" impl, then what kind of custom - /// coercion is it? This applies to impls of `CoerceUnsized` for - /// structs, primarily, where we store a bit of info about which - /// fields need to be coerced. - pub custom_kind: Option<CustomCoerceUnsized>, -} - -#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, HashStable)] -pub enum CustomCoerceUnsized { - /// Records the index of the field being coerced. - Struct(usize), -} diff --git a/src/librustc/ty/binding.rs b/src/librustc/ty/binding.rs deleted file mode 100644 index 5ee88115090..00000000000 --- a/src/librustc/ty/binding.rs +++ /dev/null @@ -1,22 +0,0 @@ -use rustc_hir::BindingAnnotation; -use rustc_hir::BindingAnnotation::*; -use rustc_hir::Mutability; - -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy, HashStable)] -pub enum BindingMode { - BindByReference(Mutability), - BindByValue(Mutability), -} - -CloneTypeFoldableAndLiftImpls! { BindingMode, } - -impl BindingMode { - pub fn convert(ba: BindingAnnotation) -> BindingMode { - match ba { - Unannotated => BindingMode::BindByValue(Mutability::Not), - Mutable => BindingMode::BindByValue(Mutability::Mut), - Ref => BindingMode::BindByReference(Mutability::Not), - RefMut => BindingMode::BindByReference(Mutability::Mut), - } - } -} diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs deleted file mode 100644 index 5ba3f80b822..00000000000 --- a/src/librustc/ty/cast.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Helpers for handling cast expressions, used in both -// typeck and codegen. - -use crate::ty::{self, Ty}; - -use rustc_macros::HashStable; -use syntax::ast; - -/// Types that are represented as ints. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum IntTy { - U(ast::UintTy), - I, - CEnum, - Bool, - Char, -} - -// Valid types for the result of a non-coercion cast -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum CastTy<'tcx> { - /// Various types that are represented as ints and handled mostly - /// in the same way, merged for easier matching. - Int(IntTy), - /// Floating-Point types - Float, - /// Function Pointers - FnPtr, - /// Raw pointers - Ptr(ty::TypeAndMut<'tcx>), -} - -/// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs) -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub enum CastKind { - CoercionCast, - PtrPtrCast, - PtrAddrCast, - AddrPtrCast, - NumericCast, - EnumCast, - PrimIntCast, - U8CharCast, - ArrayPtrCast, - FnPtrPtrCast, - FnPtrAddrCast, -} - -impl<'tcx> CastTy<'tcx> { - /// Returns `Some` for integral/pointer casts. - /// casts like unsizing casts will return `None` - pub fn from_ty(t: Ty<'tcx>) -> Option<CastTy<'tcx>> { - match t.kind { - ty::Bool => Some(CastTy::Int(IntTy::Bool)), - ty::Char => Some(CastTy::Int(IntTy::Char)), - ty::Int(_) => Some(CastTy::Int(IntTy::I)), - ty::Infer(ty::InferTy::IntVar(_)) => Some(CastTy::Int(IntTy::I)), - ty::Infer(ty::InferTy::FloatVar(_)) => Some(CastTy::Float), - ty::Uint(u) => Some(CastTy::Int(IntTy::U(u))), - ty::Float(_) => Some(CastTy::Float), - ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), - ty::RawPtr(mt) => Some(CastTy::Ptr(mt)), - ty::FnPtr(..) => Some(CastTy::FnPtr), - _ => None, - } - } -} diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs deleted file mode 100644 index c305999a64b..00000000000 --- a/src/librustc/ty/codec.rs +++ /dev/null @@ -1,494 +0,0 @@ -// This module contains some shared code for encoding and decoding various -// things from the `ty` module, and in particular implements support for -// "shorthands" which allow to have pointers back into the already encoded -// stream instead of re-encoding the same thing twice. -// -// The functionality in here is shared between persisting to crate metadata and -// persisting to incr. comp. caches. - -use crate::arena::ArenaAllocatable; -use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; -use crate::mir::{self, interpret::Allocation}; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, List, Ty, TyCtxt}; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::{CrateNum, DefId}; -use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; -use rustc_span::Span; -use std::hash::Hash; -use std::intrinsics; - -/// The shorthand encoding uses an enum's variant index `usize` -/// and is offset by this value so it never matches a real variant. -/// This offset is also chosen so that the first byte is never < 0x80. -pub const SHORTHAND_OFFSET: usize = 0x80; - -pub trait EncodableWithShorthand: Clone + Eq + Hash { - type Variant: Encodable; - fn variant(&self) -> &Self::Variant; -} - -#[allow(rustc::usage_of_ty_tykind)] -impl<'tcx> EncodableWithShorthand for Ty<'tcx> { - type Variant = ty::TyKind<'tcx>; - fn variant(&self) -> &Self::Variant { - &self.kind - } -} - -impl<'tcx> EncodableWithShorthand for ty::Predicate<'tcx> { - type Variant = ty::Predicate<'tcx>; - fn variant(&self) -> &Self::Variant { - self - } -} - -pub trait TyEncoder: Encoder { - fn position(&self) -> usize; -} - -impl TyEncoder for opaque::Encoder { - #[inline] - fn position(&self) -> usize { - self.position() - } -} - -/// Encode the given value or a previously cached shorthand. -pub fn encode_with_shorthand<E, T, M>(encoder: &mut E, value: &T, cache: M) -> Result<(), E::Error> -where - E: TyEncoder, - M: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<T, usize>, - T: EncodableWithShorthand, -{ - let existing_shorthand = cache(encoder).get(value).cloned(); - if let Some(shorthand) = existing_shorthand { - return encoder.emit_usize(shorthand); - } - - let variant = value.variant(); - - let start = encoder.position(); - variant.encode(encoder)?; - let len = encoder.position() - start; - - // The shorthand encoding uses the same usize as the - // discriminant, with an offset so they can't conflict. - let discriminant = intrinsics::discriminant_value(variant); - assert!(discriminant < SHORTHAND_OFFSET as u64); - let shorthand = start + SHORTHAND_OFFSET; - - // Get the number of bits that leb128 could fit - // in the same space as the fully encoded type. - let leb128_bits = len * 7; - - // Check that the shorthand is a not longer than the - // full encoding itself, i.e., it's an obvious win. - if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) { - cache(encoder).insert(value.clone(), shorthand); - } - - Ok(()) -} - -pub fn encode_spanned_predicates<'tcx, E, C>( - encoder: &mut E, - predicates: &'tcx [(ty::Predicate<'tcx>, Span)], - cache: C, -) -> Result<(), E::Error> -where - E: TyEncoder, - C: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<ty::Predicate<'tcx>, usize>, -{ - predicates.len().encode(encoder)?; - for (predicate, span) in predicates { - encode_with_shorthand(encoder, predicate, &cache)?; - span.encode(encoder)?; - } - Ok(()) -} - -pub trait TyDecoder<'tcx>: Decoder { - fn tcx(&self) -> TyCtxt<'tcx>; - - fn peek_byte(&self) -> u8; - - fn position(&self) -> usize; - - fn cached_ty_for_shorthand<F>( - &mut self, - shorthand: usize, - or_insert_with: F, - ) -> Result<Ty<'tcx>, Self::Error> - where - F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>; - - fn with_position<F, R>(&mut self, pos: usize, f: F) -> R - where - F: FnOnce(&mut Self) -> R; - - fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum; - - fn positioned_at_shorthand(&self) -> bool { - (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0 - } -} - -#[inline] -pub fn decode_arena_allocable<D, T: ArenaAllocatable + Decodable>( - decoder: &mut D, -) -> Result<&'tcx T, D::Error> -where - D: TyDecoder<'tcx>, -{ - Ok(decoder.tcx().arena.alloc(Decodable::decode(decoder)?)) -} - -#[inline] -pub fn decode_arena_allocable_slice<D, T: ArenaAllocatable + Decodable>( - decoder: &mut D, -) -> Result<&'tcx [T], D::Error> -where - D: TyDecoder<'tcx>, -{ - Ok(decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable>::decode(decoder)?)) -} - -#[inline] -pub fn decode_cnum<D>(decoder: &mut D) -> Result<CrateNum, D::Error> -where - D: TyDecoder<'tcx>, -{ - let cnum = CrateNum::from_u32(u32::decode(decoder)?); - Ok(decoder.map_encoded_cnum_to_current(cnum)) -} - -#[allow(rustc::usage_of_ty_tykind)] -#[inline] -pub fn decode_ty<D>(decoder: &mut D) -> Result<Ty<'tcx>, D::Error> -where - D: TyDecoder<'tcx>, -{ - // Handle shorthands first, if we have an usize > 0x80. - if decoder.positioned_at_shorthand() { - let pos = decoder.read_usize()?; - assert!(pos >= SHORTHAND_OFFSET); - let shorthand = pos - SHORTHAND_OFFSET; - - decoder.cached_ty_for_shorthand(shorthand, |decoder| { - decoder.with_position(shorthand, Ty::decode) - }) - } else { - let tcx = decoder.tcx(); - Ok(tcx.mk_ty(ty::TyKind::decode(decoder)?)) - } -} - -#[inline] -pub fn decode_spanned_predicates<D>( - decoder: &mut D, -) -> Result<&'tcx [(ty::Predicate<'tcx>, Span)], D::Error> -where - D: TyDecoder<'tcx>, -{ - let tcx = decoder.tcx(); - Ok(tcx.arena.alloc_from_iter( - (0..decoder.read_usize()?) - .map(|_| { - // Handle shorthands first, if we have an usize > 0x80. - let predicate = if decoder.positioned_at_shorthand() { - let pos = decoder.read_usize()?; - assert!(pos >= SHORTHAND_OFFSET); - let shorthand = pos - SHORTHAND_OFFSET; - - decoder.with_position(shorthand, ty::Predicate::decode) - } else { - ty::Predicate::decode(decoder) - }?; - Ok((predicate, Decodable::decode(decoder)?)) - }) - .collect::<Result<Vec<_>, _>>()?, - )) -} - -#[inline] -pub fn decode_substs<D>(decoder: &mut D) -> Result<SubstsRef<'tcx>, D::Error> -where - D: TyDecoder<'tcx>, -{ - let len = decoder.read_usize()?; - let tcx = decoder.tcx(); - Ok(tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))?) -} - -#[inline] -pub fn decode_place<D>(decoder: &mut D) -> Result<mir::Place<'tcx>, D::Error> -where - D: TyDecoder<'tcx>, -{ - let local: mir::Local = Decodable::decode(decoder)?; - let len = decoder.read_usize()?; - let projection: &'tcx List<mir::PlaceElem<'tcx>> = - decoder.tcx().mk_place_elems((0..len).map(|_| Decodable::decode(decoder)))?; - Ok(mir::Place { local, projection }) -} - -#[inline] -pub fn decode_region<D>(decoder: &mut D) -> Result<ty::Region<'tcx>, D::Error> -where - D: TyDecoder<'tcx>, -{ - Ok(decoder.tcx().mk_region(Decodable::decode(decoder)?)) -} - -#[inline] -pub fn decode_ty_slice<D>(decoder: &mut D) -> Result<&'tcx ty::List<Ty<'tcx>>, D::Error> -where - D: TyDecoder<'tcx>, -{ - let len = decoder.read_usize()?; - Ok(decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))?) -} - -#[inline] -pub fn decode_adt_def<D>(decoder: &mut D) -> Result<&'tcx ty::AdtDef, D::Error> -where - D: TyDecoder<'tcx>, -{ - let def_id = DefId::decode(decoder)?; - Ok(decoder.tcx().adt_def(def_id)) -} - -#[inline] -pub fn decode_existential_predicate_slice<D>( - decoder: &mut D, -) -> Result<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>, D::Error> -where - D: TyDecoder<'tcx>, -{ - let len = decoder.read_usize()?; - Ok(decoder.tcx().mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?) -} - -#[inline] -pub fn decode_canonical_var_infos<D>(decoder: &mut D) -> Result<CanonicalVarInfos<'tcx>, D::Error> -where - D: TyDecoder<'tcx>, -{ - let len = decoder.read_usize()?; - let interned: Result<Vec<CanonicalVarInfo>, _> = - (0..len).map(|_| Decodable::decode(decoder)).collect(); - Ok(decoder.tcx().intern_canonical_var_infos(interned?.as_slice())) -} - -#[inline] -pub fn decode_const<D>(decoder: &mut D) -> Result<&'tcx ty::Const<'tcx>, D::Error> -where - D: TyDecoder<'tcx>, -{ - Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?)) -} - -#[inline] -pub fn decode_allocation<D>(decoder: &mut D) -> Result<&'tcx Allocation, D::Error> -where - D: TyDecoder<'tcx>, -{ - Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?)) -} - -#[macro_export] -macro_rules! __impl_decoder_methods { - ($($name:ident -> $ty:ty;)*) => { - $( - #[inline] - fn $name(&mut self) -> Result<$ty, Self::Error> { - self.opaque.$name() - } - )* - } -} - -#[macro_export] -macro_rules! impl_arena_allocatable_decoder { - ([]$args:tt) => {}; - ([decode $(, $attrs:ident)*] - [[$DecoderName:ident [$($typaram:tt),*]], [$name:ident: $ty:ty], $tcx:lifetime]) => { - impl<$($typaram),*> SpecializedDecoder<&$tcx $ty> for $DecoderName<$($typaram),*> { - #[inline] - fn specialized_decode(&mut self) -> Result<&$tcx $ty, Self::Error> { - decode_arena_allocable(self) - } - } - - impl<$($typaram),*> SpecializedDecoder<&$tcx [$ty]> for $DecoderName<$($typaram),*> { - #[inline] - fn specialized_decode(&mut self) -> Result<&$tcx [$ty], Self::Error> { - decode_arena_allocable_slice(self) - } - } - }; - ([$ignore:ident $(, $attrs:ident)*]$args:tt) => { - impl_arena_allocatable_decoder!([$($attrs),*]$args); - }; -} - -#[macro_export] -macro_rules! impl_arena_allocatable_decoders { - ($args:tt, [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => { - $( - impl_arena_allocatable_decoder!($a [$args, [$name: $ty], $tcx]); - )* - } -} - -#[macro_export] -macro_rules! implement_ty_decoder { - ($DecoderName:ident <$($typaram:tt),*>) => { - mod __ty_decoder_impl { - use std::borrow::Cow; - - use rustc_serialize::{Decoder, SpecializedDecoder}; - - use $crate::infer::canonical::CanonicalVarInfos; - use $crate::ty; - use $crate::ty::codec::*; - use $crate::ty::subst::SubstsRef; - use rustc_hir::def_id::{CrateNum}; - - use rustc_span::Span; - - use super::$DecoderName; - - impl<$($typaram ),*> Decoder for $DecoderName<$($typaram),*> { - type Error = String; - - __impl_decoder_methods! { - read_nil -> (); - - read_u128 -> u128; - read_u64 -> u64; - read_u32 -> u32; - read_u16 -> u16; - read_u8 -> u8; - read_usize -> usize; - - read_i128 -> i128; - read_i64 -> i64; - read_i32 -> i32; - read_i16 -> i16; - read_i8 -> i8; - read_isize -> isize; - - read_bool -> bool; - read_f64 -> f64; - read_f32 -> f32; - read_char -> char; - read_str -> Cow<'_, str>; - } - - fn error(&mut self, err: &str) -> Self::Error { - self.opaque.error(err) - } - } - - // FIXME(#36588): These impls are horribly unsound as they allow - // the caller to pick any lifetime for `'tcx`, including `'static`, - // by using the unspecialized proxies to them. - - arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx); - - impl<$($typaram),*> SpecializedDecoder<CrateNum> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result<CrateNum, Self::Error> { - decode_cnum(self) - } - } - - impl<$($typaram),*> SpecializedDecoder<ty::Ty<'tcx>> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result<ty::Ty<'tcx>, Self::Error> { - decode_ty(self) - } - } - - impl<$($typaram),*> SpecializedDecoder<&'tcx [(ty::Predicate<'tcx>, Span)]> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) - -> Result<&'tcx [(ty::Predicate<'tcx>, Span)], Self::Error> { - decode_spanned_predicates(self) - } - } - - impl<$($typaram),*> SpecializedDecoder<SubstsRef<'tcx>> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result<SubstsRef<'tcx>, Self::Error> { - decode_substs(self) - } - } - - impl<$($typaram),*> SpecializedDecoder<$crate::mir::Place<'tcx>> - for $DecoderName<$($typaram),*> { - fn specialized_decode( - &mut self - ) -> Result<$crate::mir::Place<'tcx>, Self::Error> { - decode_place(self) - } - } - - impl<$($typaram),*> SpecializedDecoder<ty::Region<'tcx>> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result<ty::Region<'tcx>, Self::Error> { - decode_region(self) - } - } - - impl<$($typaram),*> SpecializedDecoder<&'tcx ty::List<ty::Ty<'tcx>>> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) - -> Result<&'tcx ty::List<ty::Ty<'tcx>>, Self::Error> { - decode_ty_slice(self) - } - } - - impl<$($typaram),*> SpecializedDecoder<&'tcx ty::AdtDef> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result<&'tcx ty::AdtDef, Self::Error> { - decode_adt_def(self) - } - } - - impl<$($typaram),*> SpecializedDecoder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) - -> Result<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>, Self::Error> { - decode_existential_predicate_slice(self) - } - } - - impl<$($typaram),*> SpecializedDecoder<CanonicalVarInfos<'tcx>> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) - -> Result<CanonicalVarInfos<'tcx>, Self::Error> { - decode_canonical_var_infos(self) - } - } - - impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::Const<'tcx>> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { - decode_const(self) - } - } - - impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation> - for $DecoderName<$($typaram),*> { - fn specialized_decode( - &mut self - ) -> Result<&'tcx $crate::mir::interpret::Allocation, Self::Error> { - decode_allocation(self) - } - } - } - } -} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs deleted file mode 100644 index 823cbf0966d..00000000000 --- a/src/librustc/ty/context.rs +++ /dev/null @@ -1,2796 +0,0 @@ -//! Type context book-keeping. - -use crate::arena::Arena; -use crate::dep_graph::DepGraph; -use crate::dep_graph::{self, DepConstructor}; -use crate::hir::exports::Export; -use crate::hir::map as hir_map; -use crate::hir::map::{DefPathData, DefPathHash}; -use crate::ich::{NodeIdHashingMode, StableHashingContext}; -use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::{struct_lint_level, LintSource}; -use crate::middle; -use crate::middle::cstore::CrateStoreDyn; -use crate::middle::cstore::EncodedMetadata; -use crate::middle::lang_items; -use crate::middle::lang_items::PanicLocationLangItem; -use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; -use crate::middle::stability; -use crate::mir::interpret::{Allocation, ConstValue, Scalar}; -use crate::mir::{ - interpret, BodyAndCache, Field, Local, Place, PlaceElem, ProjectionKind, Promoted, -}; -use crate::traits; -use crate::traits::{Clause, Clauses, Goal, GoalKind, Goals}; -use crate::ty::free_region_map::FreeRegionMap; -use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx}; -use crate::ty::query; -use crate::ty::steal::Steal; -use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; -use crate::ty::subst::{GenericArgKind, UserSubsts}; -use crate::ty::CanonicalPolyFnSig; -use crate::ty::GenericParamDefKind; -use crate::ty::RegionKind; -use crate::ty::ReprOptions; -use crate::ty::TyKind::*; -use crate::ty::{self, DefIdTree, Ty, TypeAndMut}; -use crate::ty::{AdtDef, AdtKind, Const, Region}; -use crate::ty::{BindingMode, BoundVar}; -use crate::ty::{ConstVid, FloatVar, FloatVid, IntVar, IntVid, TyVar, TyVid}; -use crate::ty::{ExistentialPredicate, InferTy, ParamTy, PolyFnSig, Predicate, ProjectionTy}; -use crate::ty::{InferConst, ParamConst}; -use crate::ty::{List, TyKind, TyS}; -use crate::util::common::ErrorReported; -use rustc::lint::LintDiagnosticBuilder; -use rustc_attr as attr; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; -use rustc_data_structures::stable_hasher::{ - hash_stable_hashmap, HashStable, StableHasher, StableVec, -}; -use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; -use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex, LOCAL_CRATE}; -use rustc_hir::{HirId, Node, TraitCandidate}; -use rustc_hir::{ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet}; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_macros::HashStable; -use rustc_session::config::CrateType; -use rustc_session::config::{BorrowckMode, OutputFilenames}; -use rustc_session::lint::{Level, Lint}; -use rustc_session::Session; -use rustc_span::source_map::MultiSpan; -use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; -use rustc_target::spec::abi; -use syntax::ast; -use syntax::expand::allocator::AllocatorKind; -use syntax::node_id::NodeMap; - -use smallvec::SmallVec; -use std::any::Any; -use std::borrow::Borrow; -use std::cmp::Ordering; -use std::collections::hash_map::{self, Entry}; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::iter; -use std::mem; -use std::ops::{Bound, Deref}; -use std::sync::Arc; - -type InternedSet<'tcx, T> = ShardedHashMap<Interned<'tcx, T>, ()>; - -pub struct CtxtInterners<'tcx> { - /// The arena that types, regions, etc. are allocated from. - arena: &'tcx WorkerLocal<Arena<'tcx>>, - - /// Specifically use a speedy hash algorithm for these hash sets, since - /// they're accessed quite often. - type_: InternedSet<'tcx, TyS<'tcx>>, - type_list: InternedSet<'tcx, List<Ty<'tcx>>>, - substs: InternedSet<'tcx, InternalSubsts<'tcx>>, - canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo>>, - region: InternedSet<'tcx, RegionKind>, - existential_predicates: InternedSet<'tcx, List<ExistentialPredicate<'tcx>>>, - predicates: InternedSet<'tcx, List<Predicate<'tcx>>>, - clauses: InternedSet<'tcx, List<Clause<'tcx>>>, - goal: InternedSet<'tcx, GoalKind<'tcx>>, - goal_list: InternedSet<'tcx, List<Goal<'tcx>>>, - projs: InternedSet<'tcx, List<ProjectionKind>>, - place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>, - const_: InternedSet<'tcx, Const<'tcx>>, -} - -impl<'tcx> CtxtInterners<'tcx> { - fn new(arena: &'tcx WorkerLocal<Arena<'tcx>>) -> CtxtInterners<'tcx> { - CtxtInterners { - arena, - type_: Default::default(), - type_list: Default::default(), - substs: Default::default(), - region: Default::default(), - existential_predicates: Default::default(), - canonical_var_infos: Default::default(), - predicates: Default::default(), - clauses: Default::default(), - goal: Default::default(), - goal_list: Default::default(), - projs: Default::default(), - place_elems: Default::default(), - const_: Default::default(), - } - } - - /// Interns a type. - #[allow(rustc::usage_of_ty_tykind)] - #[inline(never)] - fn intern_ty(&self, kind: TyKind<'tcx>) -> Ty<'tcx> { - self.type_ - .intern(kind, |kind| { - let flags = super::flags::FlagComputation::for_kind(&kind); - - let ty_struct = TyS { - kind, - flags: flags.flags, - outer_exclusive_binder: flags.outer_exclusive_binder, - }; - - Interned(self.arena.alloc(ty_struct)) - }) - .0 - } -} - -pub struct CommonTypes<'tcx> { - pub unit: Ty<'tcx>, - pub bool: Ty<'tcx>, - pub char: Ty<'tcx>, - pub isize: Ty<'tcx>, - pub i8: Ty<'tcx>, - pub i16: Ty<'tcx>, - pub i32: Ty<'tcx>, - pub i64: Ty<'tcx>, - pub i128: Ty<'tcx>, - pub usize: Ty<'tcx>, - pub u8: Ty<'tcx>, - pub u16: Ty<'tcx>, - pub u32: Ty<'tcx>, - pub u64: Ty<'tcx>, - pub u128: Ty<'tcx>, - pub f32: Ty<'tcx>, - pub f64: Ty<'tcx>, - pub never: Ty<'tcx>, - pub self_param: Ty<'tcx>, - pub err: Ty<'tcx>, - - /// Dummy type used for the `Self` of a `TraitRef` created for converting - /// a trait object, and which gets removed in `ExistentialTraitRef`. - /// This type must not appear anywhere in other converted types. - pub trait_object_dummy_self: Ty<'tcx>, -} - -pub struct CommonLifetimes<'tcx> { - /// `ReEmpty` in the root universe. - pub re_root_empty: Region<'tcx>, - - /// `ReStatic` - pub re_static: Region<'tcx>, - - /// Erased region, used after type-checking - pub re_erased: Region<'tcx>, -} - -pub struct CommonConsts<'tcx> { - pub err: &'tcx Const<'tcx>, -} - -pub struct LocalTableInContext<'a, V> { - local_id_root: Option<DefId>, - data: &'a ItemLocalMap<V>, -} - -/// Validate that the given HirId (respectively its `local_id` part) can be -/// safely used as a key in the tables of a TypeckTable. For that to be -/// the case, the HirId must have the same `owner` as all the other IDs in -/// this table (signified by `local_id_root`). Otherwise the HirId -/// would be in a different frame of reference and using its `local_id` -/// would result in lookup errors, or worse, in silently wrong data being -/// stored/returned. -fn validate_hir_id_for_typeck_tables( - local_id_root: Option<DefId>, - hir_id: hir::HirId, - mut_access: bool, -) { - if let Some(local_id_root) = local_id_root { - if hir_id.owner != local_id_root.index { - ty::tls::with(|tcx| { - bug!( - "node {} with HirId::owner {:?} cannot be placed in \ - TypeckTables with local_id_root {:?}", - tcx.hir().node_to_string(hir_id), - DefId::local(hir_id.owner), - local_id_root - ) - }); - } - } else { - // We use "Null Object" TypeckTables in some of the analysis passes. - // These are just expected to be empty and their `local_id_root` is - // `None`. Therefore we cannot verify whether a given `HirId` would - // be a valid key for the given table. Instead we make sure that - // nobody tries to write to such a Null Object table. - if mut_access { - bug!("access to invalid TypeckTables") - } - } -} - -impl<'a, V> LocalTableInContext<'a, V> { - pub fn contains_key(&self, id: hir::HirId) -> bool { - validate_hir_id_for_typeck_tables(self.local_id_root, id, false); - self.data.contains_key(&id.local_id) - } - - pub fn get(&self, id: hir::HirId) -> Option<&V> { - validate_hir_id_for_typeck_tables(self.local_id_root, id, false); - self.data.get(&id.local_id) - } - - pub fn iter(&self) -> hash_map::Iter<'_, hir::ItemLocalId, V> { - self.data.iter() - } -} - -impl<'a, V> ::std::ops::Index<hir::HirId> for LocalTableInContext<'a, V> { - type Output = V; - - fn index(&self, key: hir::HirId) -> &V { - self.get(key).expect("LocalTableInContext: key not found") - } -} - -pub struct LocalTableInContextMut<'a, V> { - local_id_root: Option<DefId>, - data: &'a mut ItemLocalMap<V>, -} - -impl<'a, V> LocalTableInContextMut<'a, V> { - pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> { - validate_hir_id_for_typeck_tables(self.local_id_root, id, true); - self.data.get_mut(&id.local_id) - } - - pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> { - validate_hir_id_for_typeck_tables(self.local_id_root, id, true); - self.data.entry(id.local_id) - } - - pub fn insert(&mut self, id: hir::HirId, val: V) -> Option<V> { - validate_hir_id_for_typeck_tables(self.local_id_root, id, true); - self.data.insert(id.local_id, val) - } - - pub fn remove(&mut self, id: hir::HirId) -> Option<V> { - validate_hir_id_for_typeck_tables(self.local_id_root, id, true); - self.data.remove(&id.local_id) - } -} - -/// All information necessary to validate and reveal an `impl Trait`. -#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] -pub struct ResolvedOpaqueTy<'tcx> { - /// The revealed type as seen by this function. - pub concrete_type: Ty<'tcx>, - /// Generic parameters on the opaque type as passed by this function. - /// For `type Foo<A, B> = impl Bar<A, B>; fn foo<T, U>() -> Foo<T, U> { .. }` - /// this is `[T, U]`, not `[A, B]`. - pub substs: SubstsRef<'tcx>, -} - -/// Whenever a value may be live across a generator yield, the type of that value winds up in the -/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such -/// captured types that can be useful for diagnostics. In particular, it stores the span that -/// caused a given type to be recorded, along with the scope that enclosed the value (which can -/// be used to find the await that the value is live across). -/// -/// For example: -/// -/// ```ignore (pseudo-Rust) -/// async move { -/// let x: T = ...; -/// foo.await -/// ... -/// } -/// ``` -/// -/// Here, we would store the type `T`, the span of the value `x`, and the "scope-span" for -/// the scope that contains `x`. -#[derive(RustcEncodable, RustcDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)] -pub struct GeneratorInteriorTypeCause<'tcx> { - /// Type of the captured binding. - pub ty: Ty<'tcx>, - /// Span of the binding that was captured. - pub span: Span, - /// Span of the scope of the captured binding. - pub scope_span: Option<Span>, - /// Expr which the type evaluated from. - pub expr: Option<hir::HirId>, -} - -#[derive(RustcEncodable, RustcDecodable, Debug)] -pub struct TypeckTables<'tcx> { - /// The HirId::owner all ItemLocalIds in this table are relative to. - pub local_id_root: Option<DefId>, - - /// Resolved definitions for `<T>::X` associated paths and - /// method calls, including those of overloaded operators. - type_dependent_defs: ItemLocalMap<Result<(DefKind, DefId), ErrorReported>>, - - /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`) - /// or patterns (`S { field }`). The index is often useful by itself, but to learn more - /// about the field you also need definition of the variant to which the field - /// belongs, but it may not exist if it's a tuple field (`tuple.0`). - field_indices: ItemLocalMap<usize>, - - /// Stores the types for various nodes in the AST. Note that this table - /// is not guaranteed to be populated until after typeck. See - /// typeck::check::fn_ctxt for details. - node_types: ItemLocalMap<Ty<'tcx>>, - - /// Stores the type parameters which were substituted to obtain the type - /// of this node. This only applies to nodes that refer to entities - /// parameterized by type parameters, such as generic fns, types, or - /// other items. - node_substs: ItemLocalMap<SubstsRef<'tcx>>, - - /// This will either store the canonicalized types provided by the user - /// or the substitutions that the user explicitly gave (if any) attached - /// to `id`. These will not include any inferred values. The canonical form - /// is used to capture things like `_` or other unspecified values. - /// - /// For example, if the user wrote `foo.collect::<Vec<_>>()`, then the - /// canonical substitutions would include only `for<X> { Vec<X> }`. - /// - /// See also `AscribeUserType` statement in MIR. - user_provided_types: ItemLocalMap<CanonicalUserType<'tcx>>, - - /// Stores the canonicalized types provided by the user. See also - /// `AscribeUserType` statement in MIR. - pub user_provided_sigs: DefIdMap<CanonicalPolyFnSig<'tcx>>, - - adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>, - - /// Stores the actual binding mode for all instances of hir::BindingAnnotation. - pat_binding_modes: ItemLocalMap<BindingMode>, - - /// Stores the types which were implicitly dereferenced in pattern binding modes - /// for later usage in HAIR lowering. For example, - /// - /// ``` - /// match &&Some(5i32) { - /// Some(n) => {}, - /// _ => {}, - /// } - /// ``` - /// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored. - /// - /// See: - /// https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions - pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>, - - /// Borrows - pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, - - /// Records the reasons that we picked the kind of each closure; - /// not all closures are present in the map. - closure_kind_origins: ItemLocalMap<(Span, ast::Name)>, - - /// For each fn, records the "liberated" types of its arguments - /// and return type. Liberated means that all bound regions - /// (including late-bound regions) are replaced with free - /// equivalents. This table is not used in codegen (since regions - /// are erased there) and hence is not serialized to metadata. - liberated_fn_sigs: ItemLocalMap<ty::FnSig<'tcx>>, - - /// For each FRU expression, record the normalized types of the fields - /// of the struct - this is needed because it is non-trivial to - /// normalize while preserving regions. This table is used only in - /// MIR construction and hence is not serialized to metadata. - fru_field_types: ItemLocalMap<Vec<Ty<'tcx>>>, - - /// For every coercion cast we add the HIR node ID of the cast - /// expression to this set. - coercion_casts: ItemLocalSet, - - /// Set of trait imports actually used in the method resolution. - /// This is used for warning unused imports. During type - /// checking, this `Lrc` should not be cloned: it must have a ref-count - /// of 1 so that we can insert things into the set mutably. - pub used_trait_imports: Lrc<DefIdSet>, - - /// If any errors occurred while type-checking this body, - /// this field will be set to `true`. - pub tainted_by_errors: bool, - - /// Stores the free-region relationships that were deduced from - /// its where-clauses and parameter types. These are then - /// read-again by borrowck. - pub free_region_map: FreeRegionMap<'tcx>, - - /// All the opaque types that are restricted to concrete types - /// by this function. - pub concrete_opaque_types: FxHashMap<DefId, ResolvedOpaqueTy<'tcx>>, - - /// Given the closure ID this map provides the list of UpvarIDs used by it. - /// The upvarID contains the HIR node ID and it also contains the full path - /// leading to the member of the struct or tuple that is used instead of the - /// entire variable. - pub upvar_list: ty::UpvarListMap, - - /// Stores the type, expression, span and optional scope span of all types - /// that are live across the yield of this generator (if a generator). - pub generator_interior_types: Vec<GeneratorInteriorTypeCause<'tcx>>, -} - -impl<'tcx> TypeckTables<'tcx> { - pub fn empty(local_id_root: Option<DefId>) -> TypeckTables<'tcx> { - TypeckTables { - local_id_root, - type_dependent_defs: Default::default(), - field_indices: Default::default(), - user_provided_types: Default::default(), - user_provided_sigs: Default::default(), - node_types: Default::default(), - node_substs: Default::default(), - adjustments: Default::default(), - pat_binding_modes: Default::default(), - pat_adjustments: Default::default(), - upvar_capture_map: Default::default(), - closure_kind_origins: Default::default(), - liberated_fn_sigs: Default::default(), - fru_field_types: Default::default(), - coercion_casts: Default::default(), - used_trait_imports: Lrc::new(Default::default()), - tainted_by_errors: false, - free_region_map: Default::default(), - concrete_opaque_types: Default::default(), - upvar_list: Default::default(), - generator_interior_types: Default::default(), - } - } - - /// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node. - pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res { - match *qpath { - hir::QPath::Resolved(_, ref path) => path.res, - hir::QPath::TypeRelative(..) => self - .type_dependent_def(id) - .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), - } - } - - pub fn type_dependent_defs( - &self, - ) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorReported>> { - LocalTableInContext { local_id_root: self.local_id_root, data: &self.type_dependent_defs } - } - - pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> { - validate_hir_id_for_typeck_tables(self.local_id_root, id, false); - self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok()) - } - - pub fn type_dependent_def_id(&self, id: HirId) -> Option<DefId> { - self.type_dependent_def(id).map(|(_, def_id)| def_id) - } - - pub fn type_dependent_defs_mut( - &mut self, - ) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorReported>> { - LocalTableInContextMut { - local_id_root: self.local_id_root, - data: &mut self.type_dependent_defs, - } - } - - pub fn field_indices(&self) -> LocalTableInContext<'_, usize> { - LocalTableInContext { local_id_root: self.local_id_root, data: &self.field_indices } - } - - pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> { - LocalTableInContextMut { local_id_root: self.local_id_root, data: &mut self.field_indices } - } - - pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> { - LocalTableInContext { local_id_root: self.local_id_root, data: &self.user_provided_types } - } - - pub fn user_provided_types_mut( - &mut self, - ) -> LocalTableInContextMut<'_, CanonicalUserType<'tcx>> { - LocalTableInContextMut { - local_id_root: self.local_id_root, - data: &mut self.user_provided_types, - } - } - - pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> { - LocalTableInContext { local_id_root: self.local_id_root, data: &self.node_types } - } - - pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> { - LocalTableInContextMut { local_id_root: self.local_id_root, data: &mut self.node_types } - } - - pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> { - self.node_type_opt(id).unwrap_or_else(|| { - bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id))) - }) - } - - pub fn node_type_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> { - validate_hir_id_for_typeck_tables(self.local_id_root, id, false); - self.node_types.get(&id.local_id).cloned() - } - - pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<'_, SubstsRef<'tcx>> { - LocalTableInContextMut { local_id_root: self.local_id_root, data: &mut self.node_substs } - } - - pub fn node_substs(&self, id: hir::HirId) -> SubstsRef<'tcx> { - validate_hir_id_for_typeck_tables(self.local_id_root, id, false); - self.node_substs.get(&id.local_id).cloned().unwrap_or_else(|| InternalSubsts::empty()) - } - - pub fn node_substs_opt(&self, id: hir::HirId) -> Option<SubstsRef<'tcx>> { - validate_hir_id_for_typeck_tables(self.local_id_root, id, false); - self.node_substs.get(&id.local_id).cloned() - } - - // Returns the type of a pattern as a monotype. Like @expr_ty, this function - // doesn't provide type parameter substitutions. - pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> { - self.node_type(pat.hir_id) - } - - pub fn pat_ty_opt(&self, pat: &hir::Pat<'_>) -> Option<Ty<'tcx>> { - self.node_type_opt(pat.hir_id) - } - - // Returns the type of an expression as a monotype. - // - // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in - // some cases, we insert `Adjustment` annotations such as auto-deref or - // auto-ref. The type returned by this function does not consider such - // adjustments. See `expr_ty_adjusted()` instead. - // - // NB (2): This type doesn't provide type parameter substitutions; e.g., if you - // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize" - // instead of "fn(ty) -> T with T = isize". - pub fn expr_ty(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> { - self.node_type(expr.hir_id) - } - - pub fn expr_ty_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> { - self.node_type_opt(expr.hir_id) - } - - pub fn adjustments(&self) -> LocalTableInContext<'_, Vec<ty::adjustment::Adjustment<'tcx>>> { - LocalTableInContext { local_id_root: self.local_id_root, data: &self.adjustments } - } - - pub fn adjustments_mut( - &mut self, - ) -> LocalTableInContextMut<'_, Vec<ty::adjustment::Adjustment<'tcx>>> { - LocalTableInContextMut { local_id_root: self.local_id_root, data: &mut self.adjustments } - } - - pub fn expr_adjustments(&self, expr: &hir::Expr<'_>) -> &[ty::adjustment::Adjustment<'tcx>] { - validate_hir_id_for_typeck_tables(self.local_id_root, expr.hir_id, false); - self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..]) - } - - /// Returns the type of `expr`, considering any `Adjustment` - /// entry recorded for that expression. - pub fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> { - self.expr_adjustments(expr).last().map_or_else(|| self.expr_ty(expr), |adj| adj.target) - } - - pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> { - self.expr_adjustments(expr).last().map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr)) - } - - pub fn is_method_call(&self, expr: &hir::Expr<'_>) -> bool { - // Only paths and method calls/overloaded operators have - // entries in type_dependent_defs, ignore the former here. - if let hir::ExprKind::Path(_) = expr.kind { - return false; - } - - match self.type_dependent_defs().get(expr.hir_id) { - Some(Ok((DefKind::Method, _))) => true, - _ => false, - } - } - - pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> { - self.pat_binding_modes().get(id).copied().or_else(|| { - s.delay_span_bug(sp, "missing binding mode"); - None - }) - } - - pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> { - LocalTableInContext { local_id_root: self.local_id_root, data: &self.pat_binding_modes } - } - - pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> { - LocalTableInContextMut { - local_id_root: self.local_id_root, - data: &mut self.pat_binding_modes, - } - } - - pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> { - LocalTableInContext { local_id_root: self.local_id_root, data: &self.pat_adjustments } - } - - pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> { - LocalTableInContextMut { - local_id_root: self.local_id_root, - data: &mut self.pat_adjustments, - } - } - - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> { - self.upvar_capture_map[&upvar_id] - } - - pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, ast::Name)> { - LocalTableInContext { local_id_root: self.local_id_root, data: &self.closure_kind_origins } - } - - pub fn closure_kind_origins_mut(&mut self) -> LocalTableInContextMut<'_, (Span, ast::Name)> { - LocalTableInContextMut { - local_id_root: self.local_id_root, - data: &mut self.closure_kind_origins, - } - } - - pub fn liberated_fn_sigs(&self) -> LocalTableInContext<'_, ty::FnSig<'tcx>> { - LocalTableInContext { local_id_root: self.local_id_root, data: &self.liberated_fn_sigs } - } - - pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut<'_, ty::FnSig<'tcx>> { - LocalTableInContextMut { - local_id_root: self.local_id_root, - data: &mut self.liberated_fn_sigs, - } - } - - pub fn fru_field_types(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> { - LocalTableInContext { local_id_root: self.local_id_root, data: &self.fru_field_types } - } - - pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> { - LocalTableInContextMut { - local_id_root: self.local_id_root, - data: &mut self.fru_field_types, - } - } - - pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool { - validate_hir_id_for_typeck_tables(self.local_id_root, hir_id, true); - self.coercion_casts.contains(&hir_id.local_id) - } - - pub fn set_coercion_cast(&mut self, id: ItemLocalId) { - self.coercion_casts.insert(id); - } - - pub fn coercion_casts(&self) -> &ItemLocalSet { - &self.coercion_casts - } -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let ty::TypeckTables { - local_id_root, - ref type_dependent_defs, - ref field_indices, - ref user_provided_types, - ref user_provided_sigs, - ref node_types, - ref node_substs, - ref adjustments, - ref pat_binding_modes, - ref pat_adjustments, - ref upvar_capture_map, - ref closure_kind_origins, - ref liberated_fn_sigs, - ref fru_field_types, - - ref coercion_casts, - - ref used_trait_imports, - tainted_by_errors, - ref free_region_map, - ref concrete_opaque_types, - ref upvar_list, - ref generator_interior_types, - } = *self; - - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - type_dependent_defs.hash_stable(hcx, hasher); - field_indices.hash_stable(hcx, hasher); - user_provided_types.hash_stable(hcx, hasher); - user_provided_sigs.hash_stable(hcx, hasher); - node_types.hash_stable(hcx, hasher); - node_substs.hash_stable(hcx, hasher); - adjustments.hash_stable(hcx, hasher); - pat_binding_modes.hash_stable(hcx, hasher); - pat_adjustments.hash_stable(hcx, hasher); - hash_stable_hashmap(hcx, hasher, upvar_capture_map, |up_var_id, hcx| { - let ty::UpvarId { var_path, closure_expr_id } = *up_var_id; - - let local_id_root = local_id_root.expect("trying to hash invalid TypeckTables"); - - let var_owner_def_id = - DefId { krate: local_id_root.krate, index: var_path.hir_id.owner }; - let closure_def_id = - DefId { krate: local_id_root.krate, index: closure_expr_id.to_def_id().index }; - ( - hcx.def_path_hash(var_owner_def_id), - var_path.hir_id.local_id, - hcx.def_path_hash(closure_def_id), - ) - }); - - closure_kind_origins.hash_stable(hcx, hasher); - liberated_fn_sigs.hash_stable(hcx, hasher); - fru_field_types.hash_stable(hcx, hasher); - coercion_casts.hash_stable(hcx, hasher); - used_trait_imports.hash_stable(hcx, hasher); - tainted_by_errors.hash_stable(hcx, hasher); - free_region_map.hash_stable(hcx, hasher); - concrete_opaque_types.hash_stable(hcx, hasher); - upvar_list.hash_stable(hcx, hasher); - generator_interior_types.hash_stable(hcx, hasher); - }) - } -} - -rustc_index::newtype_index! { - pub struct UserTypeAnnotationIndex { - derive [HashStable] - DEBUG_FORMAT = "UserType({})", - const START_INDEX = 0, - } -} - -/// Mapping of type annotation indices to canonical user type annotations. -pub type CanonicalUserTypeAnnotations<'tcx> = - IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>; - -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable, Lift)] -pub struct CanonicalUserTypeAnnotation<'tcx> { - pub user_ty: CanonicalUserType<'tcx>, - pub span: Span, - pub inferred_ty: Ty<'tcx>, -} - -/// Canonicalized user type annotation. -pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>; - -impl CanonicalUserType<'tcx> { - /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`, - /// i.e., each thing is mapped to a canonical variable with the same index. - pub fn is_identity(&self) -> bool { - match self.value { - UserType::Ty(_) => false, - UserType::TypeOf(_, user_substs) => { - if user_substs.user_self_ty.is_some() { - return false; - } - - user_substs.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| { - match kind.unpack() { - GenericArgKind::Type(ty) => match ty.kind { - ty::Bound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(debruijn, ty::INNERMOST); - cvar == b.var - } - _ => false, - }, - - GenericArgKind::Lifetime(r) => match r { - ty::ReLateBound(debruijn, br) => { - // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(*debruijn, ty::INNERMOST); - cvar == br.assert_bound_var() - } - _ => false, - }, - - GenericArgKind::Const(ct) => match ct.val { - ty::ConstKind::Bound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(debruijn, ty::INNERMOST); - cvar == b - } - _ => false, - }, - } - }) - } - } - } -} - -/// A user-given type annotation attached to a constant. These arise -/// from constants that are named via paths, like `Foo::<A>::new` and -/// so forth. -#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable, Lift)] -pub enum UserType<'tcx> { - Ty(Ty<'tcx>), - - /// The canonical type is the result of `type_of(def_id)` with the - /// given substitutions applied. - TypeOf(DefId, UserSubsts<'tcx>), -} - -impl<'tcx> CommonTypes<'tcx> { - fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { - let mk = |ty| interners.intern_ty(ty); - - CommonTypes { - unit: mk(Tuple(List::empty())), - bool: mk(Bool), - char: mk(Char), - never: mk(Never), - err: mk(Error), - isize: mk(Int(ast::IntTy::Isize)), - i8: mk(Int(ast::IntTy::I8)), - i16: mk(Int(ast::IntTy::I16)), - i32: mk(Int(ast::IntTy::I32)), - i64: mk(Int(ast::IntTy::I64)), - i128: mk(Int(ast::IntTy::I128)), - usize: mk(Uint(ast::UintTy::Usize)), - u8: mk(Uint(ast::UintTy::U8)), - u16: mk(Uint(ast::UintTy::U16)), - u32: mk(Uint(ast::UintTy::U32)), - u64: mk(Uint(ast::UintTy::U64)), - u128: mk(Uint(ast::UintTy::U128)), - f32: mk(Float(ast::FloatTy::F32)), - f64: mk(Float(ast::FloatTy::F64)), - self_param: mk(ty::Param(ty::ParamTy { index: 0, name: kw::SelfUpper })), - - trait_object_dummy_self: mk(Infer(ty::FreshTy(0))), - } - } -} - -impl<'tcx> CommonLifetimes<'tcx> { - fn new(interners: &CtxtInterners<'tcx>) -> CommonLifetimes<'tcx> { - let mk = |r| interners.region.intern(r, |r| Interned(interners.arena.alloc(r))).0; - - CommonLifetimes { - re_root_empty: mk(RegionKind::ReEmpty(ty::UniverseIndex::ROOT)), - re_static: mk(RegionKind::ReStatic), - re_erased: mk(RegionKind::ReErased), - } - } -} - -impl<'tcx> CommonConsts<'tcx> { - fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonConsts<'tcx> { - let mk_const = |c| interners.const_.intern(c, |c| Interned(interners.arena.alloc(c))).0; - - CommonConsts { - err: mk_const(ty::Const { - val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::zst())), - ty: types.err, - }), - } - } -} - -// This struct contains information regarding the `ReFree(FreeRegion)` corresponding to a lifetime -// conflict. -#[derive(Debug)] -pub struct FreeRegionInfo { - // def id corresponding to FreeRegion - pub def_id: DefId, - // the bound region corresponding to FreeRegion - pub boundregion: ty::BoundRegion, - // checks if bound region is in Impl Item - pub is_impl_item: bool, -} - -/// The central data structure of the compiler. It stores references -/// to the various **arenas** and also houses the results of the -/// various **compiler queries** that have been performed. See the -/// [rustc guide] for more details. -/// -/// [rustc guide]: https://rust-lang.github.io/rustc-guide/ty.html -#[derive(Copy, Clone)] -#[rustc_diagnostic_item = "TyCtxt"] -pub struct TyCtxt<'tcx> { - gcx: &'tcx GlobalCtxt<'tcx>, -} - -impl<'tcx> Deref for TyCtxt<'tcx> { - type Target = &'tcx GlobalCtxt<'tcx>; - #[inline(always)] - fn deref(&self) -> &Self::Target { - &self.gcx - } -} - -pub struct GlobalCtxt<'tcx> { - pub arena: &'tcx WorkerLocal<Arena<'tcx>>, - - interners: CtxtInterners<'tcx>, - - cstore: Box<CrateStoreDyn>, - - pub sess: &'tcx Session, - - /// This only ever stores a `LintStore` but we don't want a dependency on that type here. - /// - /// FIXME(Centril): consider `dyn LintStoreMarker` once - /// we can upcast to `Any` for some additional type safety. - pub lint_store: Lrc<dyn Any + sync::Sync + sync::Send>, - - pub dep_graph: DepGraph, - - pub prof: SelfProfilerRef, - - /// Common types, pre-interned for your convenience. - pub types: CommonTypes<'tcx>, - - /// Common lifetimes, pre-interned for your convenience. - pub lifetimes: CommonLifetimes<'tcx>, - - /// Common consts, pre-interned for your convenience. - pub consts: CommonConsts<'tcx>, - - /// Resolutions of `extern crate` items produced by resolver. - extern_crate_map: NodeMap<CrateNum>, - - /// Map indicating what traits are in scope for places where this - /// is relevant; generated by resolve. - trait_map: FxHashMap<DefIndex, FxHashMap<ItemLocalId, StableVec<TraitCandidate>>>, - - /// Export map produced by name resolution. - export_map: FxHashMap<DefId, Vec<Export<hir::HirId>>>, - - /// This should usually be accessed with the `tcx.hir()` method. - pub(crate) hir_map: hir_map::Map<'tcx>, - - /// A map from `DefPathHash` -> `DefId`. Includes `DefId`s from the local crate - /// as well as all upstream crates. Only populated in incremental mode. - pub def_path_hash_to_def_id: Option<FxHashMap<DefPathHash, DefId>>, - - pub queries: query::Queries<'tcx>, - - maybe_unused_trait_imports: FxHashSet<DefId>, - maybe_unused_extern_crates: Vec<(DefId, Span)>, - /// A map of glob use to a set of names it actually imports. Currently only - /// used in save-analysis. - glob_map: FxHashMap<DefId, FxHashSet<ast::Name>>, - /// Extern prelude entries. The value is `true` if the entry was introduced - /// via `extern crate` item and not `--extern` option or compiler built-in. - pub extern_prelude: FxHashMap<ast::Name, bool>, - - // Internal cache for metadata decoding. No need to track deps on this. - pub rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>, - - /// Caches the results of trait selection. This cache is used - /// for things that do not have to do with the parameters in scope. - pub selection_cache: traits::SelectionCache<'tcx>, - - /// Caches the results of trait evaluation. This cache is used - /// for things that do not have to do with the parameters in scope. - /// Merge this with `selection_cache`? - pub evaluation_cache: traits::EvaluationCache<'tcx>, - - /// The definite name of the current crate after taking into account - /// attributes, commandline parameters, etc. - pub crate_name: Symbol, - - /// Data layout specification for the current target. - pub data_layout: TargetDataLayout, - - /// `#[stable]` and `#[unstable]` attributes - stability_interner: ShardedHashMap<&'tcx attr::Stability, ()>, - - /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes - const_stability_interner: ShardedHashMap<&'tcx attr::ConstStability, ()>, - - /// Stores the value of constants (and deduplicates the actual memory) - allocation_interner: ShardedHashMap<&'tcx Allocation, ()>, - - pub alloc_map: Lock<interpret::AllocMap<'tcx>>, - - layout_interner: ShardedHashMap<&'tcx LayoutDetails, ()>, - - output_filenames: Arc<OutputFilenames>, -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn alloc_steal_mir(self, mir: BodyAndCache<'tcx>) -> &'tcx Steal<BodyAndCache<'tcx>> { - self.arena.alloc(Steal::new(mir)) - } - - pub fn alloc_steal_promoted( - self, - promoted: IndexVec<Promoted, BodyAndCache<'tcx>>, - ) -> &'tcx Steal<IndexVec<Promoted, BodyAndCache<'tcx>>> { - self.arena.alloc(Steal::new(promoted)) - } - - pub fn intern_promoted( - self, - promoted: IndexVec<Promoted, BodyAndCache<'tcx>>, - ) -> &'tcx IndexVec<Promoted, BodyAndCache<'tcx>> { - self.arena.alloc(promoted) - } - - pub fn alloc_adt_def( - self, - did: DefId, - kind: AdtKind, - variants: IndexVec<VariantIdx, ty::VariantDef>, - repr: ReprOptions, - ) -> &'tcx ty::AdtDef { - let def = ty::AdtDef::new(self, did, kind, variants, repr); - self.arena.alloc(def) - } - - pub fn intern_const_alloc(self, alloc: Allocation) -> &'tcx Allocation { - self.allocation_interner.intern(alloc, |alloc| self.arena.alloc(alloc)) - } - - /// Allocates a read-only byte or string literal for `mir::interpret`. - pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId { - // Create an allocation that just contains these bytes. - let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes); - let alloc = self.intern_const_alloc(alloc); - self.alloc_map.lock().create_memory_alloc(alloc) - } - - pub fn intern_stability(self, stab: attr::Stability) -> &'tcx attr::Stability { - self.stability_interner.intern(stab, |stab| self.arena.alloc(stab)) - } - - pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability { - self.const_stability_interner.intern(stab, |stab| self.arena.alloc(stab)) - } - - pub fn intern_layout(self, layout: LayoutDetails) -> &'tcx LayoutDetails { - self.layout_interner.intern(layout, |layout| self.arena.alloc(layout)) - } - - /// Returns a range of the start/end indices specified with the - /// `rustc_layout_scalar_valid_range` attribute. - pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) { - let attrs = self.get_attrs(def_id); - let get = |name| { - let attr = match attrs.iter().find(|a| a.check_name(name)) { - Some(attr) => attr, - None => return Bound::Unbounded, - }; - for meta in attr.meta_item_list().expect("rustc_layout_scalar_valid_range takes args") { - match meta.literal().expect("attribute takes lit").kind { - ast::LitKind::Int(a, _) => return Bound::Included(a), - _ => span_bug!(attr.span, "rustc_layout_scalar_valid_range expects int arg"), - } - } - span_bug!(attr.span, "no arguments to `rustc_layout_scalar_valid_range` attribute"); - }; - ( - get(sym::rustc_layout_scalar_valid_range_start), - get(sym::rustc_layout_scalar_valid_range_end), - ) - } - - pub fn lift<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> { - value.lift_to_tcx(self) - } - - /// Creates a type context and call the closure with a `TyCtxt` reference - /// to the context. The closure enforces that the type context and any interned - /// value (types, substs, etc.) can only be used while `ty::tls` has a valid - /// reference to the context, to allow formatting values that need it. - pub fn create_global_ctxt( - s: &'tcx Session, - lint_store: Lrc<dyn Any + sync::Send + sync::Sync>, - local_providers: ty::query::Providers<'tcx>, - extern_providers: ty::query::Providers<'tcx>, - arena: &'tcx WorkerLocal<Arena<'tcx>>, - resolutions: ty::ResolverOutputs, - hir: hir_map::Map<'tcx>, - on_disk_query_result_cache: query::OnDiskCache<'tcx>, - crate_name: &str, - output_filenames: &OutputFilenames, - ) -> GlobalCtxt<'tcx> { - let data_layout = TargetDataLayout::parse(&s.target.target).unwrap_or_else(|err| { - s.fatal(&err); - }); - let interners = CtxtInterners::new(arena); - let common_types = CommonTypes::new(&interners); - let common_lifetimes = CommonLifetimes::new(&interners); - let common_consts = CommonConsts::new(&interners, &common_types); - let dep_graph = hir.dep_graph.clone(); - let cstore = resolutions.cstore; - let crates = cstore.crates_untracked(); - let max_cnum = crates.iter().map(|c| c.as_usize()).max().unwrap_or(0); - let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1); - providers[LOCAL_CRATE] = local_providers; - - let def_path_hash_to_def_id = if s.opts.build_dep_graph() { - let def_path_tables = crates - .iter() - .map(|&cnum| (cnum, cstore.def_path_table(cnum))) - .chain(iter::once((LOCAL_CRATE, hir.definitions().def_path_table()))); - - // Precompute the capacity of the hashmap so we don't have to - // re-allocate when populating it. - let capacity = def_path_tables.clone().map(|(_, t)| t.size()).sum::<usize>(); - - let mut map: FxHashMap<_, _> = - FxHashMap::with_capacity_and_hasher(capacity, ::std::default::Default::default()); - - for (cnum, def_path_table) in def_path_tables { - def_path_table.add_def_path_hashes_to(cnum, &mut map); - } - - Some(map) - } else { - None - }; - - let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); - for (k, v) in resolutions.trait_map { - let hir_id = hir.node_to_hir_id(k); - let map = trait_map.entry(hir_id.owner).or_default(); - let v = v - .into_iter() - .map(|tc| tc.map_import_ids(|id| hir.definitions().node_to_hir_id(id))) - .collect(); - map.insert(hir_id.local_id, StableVec::new(v)); - } - - GlobalCtxt { - sess: s, - lint_store, - cstore, - arena, - interners, - dep_graph, - prof: s.prof.clone(), - types: common_types, - lifetimes: common_lifetimes, - consts: common_consts, - extern_crate_map: resolutions.extern_crate_map, - trait_map, - export_map: resolutions - .export_map - .into_iter() - .map(|(k, v)| { - let exports: Vec<_> = - v.into_iter().map(|e| e.map_id(|id| hir.node_to_hir_id(id))).collect(); - (k, exports) - }) - .collect(), - maybe_unused_trait_imports: resolutions - .maybe_unused_trait_imports - .into_iter() - .map(|id| hir.local_def_id_from_node_id(id)) - .collect(), - maybe_unused_extern_crates: resolutions - .maybe_unused_extern_crates - .into_iter() - .map(|(id, sp)| (hir.local_def_id_from_node_id(id), sp)) - .collect(), - glob_map: resolutions - .glob_map - .into_iter() - .map(|(id, names)| (hir.local_def_id_from_node_id(id), names)) - .collect(), - extern_prelude: resolutions.extern_prelude, - hir_map: hir, - def_path_hash_to_def_id, - queries: query::Queries::new(providers, extern_providers, on_disk_query_result_cache), - rcache: Default::default(), - selection_cache: Default::default(), - evaluation_cache: Default::default(), - crate_name: Symbol::intern(crate_name), - data_layout, - layout_interner: Default::default(), - stability_interner: Default::default(), - const_stability_interner: Default::default(), - allocation_interner: Default::default(), - alloc_map: Lock::new(interpret::AllocMap::new()), - output_filenames: Arc::new(output_filenames.clone()), - } - } - - pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool { - let cname = self.crate_name(LOCAL_CRATE).as_str(); - self.sess.consider_optimizing(&cname, msg) - } - - pub fn lib_features(self) -> &'tcx middle::lib_features::LibFeatures { - self.get_lib_features(LOCAL_CRATE) - } - - /// Obtain all lang items of this crate and all dependencies (recursively) - pub fn lang_items(self) -> &'tcx middle::lang_items::LanguageItems { - self.get_lang_items(LOCAL_CRATE) - } - - /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to - /// compare against another `DefId`, since `is_diagnostic_item` is cheaper. - pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> { - self.all_diagnostic_items(LOCAL_CRATE).get(&name).copied() - } - - /// Check whether the diagnostic item with the given `name` has the given `DefId`. - pub fn is_diagnostic_item(self, name: Symbol, did: DefId) -> bool { - self.diagnostic_items(did.krate).get(&name) == Some(&did) - } - - pub fn stability(self) -> &'tcx stability::Index<'tcx> { - self.stability_index(LOCAL_CRATE) - } - - pub fn crates(self) -> &'tcx [CrateNum] { - self.all_crate_nums(LOCAL_CRATE) - } - - pub fn allocator_kind(self) -> Option<AllocatorKind> { - self.cstore.allocator_kind() - } - - pub fn features(self) -> &'tcx rustc_feature::Features { - self.features_query(LOCAL_CRATE) - } - - pub fn def_key(self, id: DefId) -> hir_map::DefKey { - if id.is_local() { self.hir().def_key(id) } else { self.cstore.def_key(id) } - } - - /// Converts a `DefId` into its fully expanded `DefPath` (every - /// `DefId` is really just an interned `DefPath`). - /// - /// Note that if `id` is not local to this crate, the result will - /// be a non-local `DefPath`. - pub fn def_path(self, id: DefId) -> hir_map::DefPath { - if id.is_local() { self.hir().def_path(id) } else { self.cstore.def_path(id) } - } - - /// Returns whether or not the crate with CrateNum 'cnum' - /// is marked as a private dependency - pub fn is_private_dep(self, cnum: CrateNum) -> bool { - if cnum == LOCAL_CRATE { false } else { self.cstore.crate_is_private_dep_untracked(cnum) } - } - - #[inline] - pub fn def_path_hash(self, def_id: DefId) -> hir_map::DefPathHash { - if def_id.is_local() { - self.hir().definitions().def_path_hash(def_id.index) - } else { - self.cstore.def_path_hash(def_id) - } - } - - pub fn def_path_debug_str(self, def_id: DefId) -> String { - // We are explicitly not going through queries here in order to get - // crate name and disambiguator since this code is called from debug!() - // statements within the query system and we'd run into endless - // recursion otherwise. - let (crate_name, crate_disambiguator) = if def_id.is_local() { - (self.crate_name, self.sess.local_crate_disambiguator()) - } else { - ( - self.cstore.crate_name_untracked(def_id.krate), - self.cstore.crate_disambiguator_untracked(def_id.krate), - ) - }; - - format!( - "{}[{}]{}", - crate_name, - // Don't print the whole crate disambiguator. That's just - // annoying in debug output. - &(crate_disambiguator.to_fingerprint().to_hex())[..4], - self.def_path(def_id).to_string_no_crate() - ) - } - - pub fn metadata_encoding_version(self) -> Vec<u8> { - self.cstore.metadata_encoding_version().to_vec() - } - - pub fn encode_metadata(self) -> EncodedMetadata { - let _prof_timer = self.prof.generic_activity("generate_crate_metadata"); - self.cstore.encode_metadata(self) - } - - // Note that this is *untracked* and should only be used within the query - // system if the result is otherwise tracked through queries - pub fn cstore_as_any(self) -> &'tcx dyn Any { - self.cstore.as_any() - } - - #[inline(always)] - pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> { - let krate = self.gcx.hir_map.untracked_krate(); - - StableHashingContext::new(self.sess, krate, self.hir().definitions(), &*self.cstore) - } - - // This method makes sure that we have a DepNode and a Fingerprint for - // every upstream crate. It needs to be called once right after the tcx is - // created. - // With full-fledged red/green, the method will probably become unnecessary - // as this will be done on-demand. - pub fn allocate_metadata_dep_nodes(self) { - // We cannot use the query versions of crates() and crate_hash(), since - // those would need the DepNodes that we are allocating here. - for cnum in self.cstore.crates_untracked() { - let dep_node = DepConstructor::CrateMetadata(self, cnum); - let crate_hash = self.cstore.crate_hash_untracked(cnum); - self.dep_graph.with_task( - dep_node, - self, - crate_hash, - |_, x| x, // No transformation needed - dep_graph::hash_result, - ); - } - } - - pub fn serialize_query_result_cache<E>(self, encoder: &mut E) -> Result<(), E::Error> - where - E: ty::codec::TyEncoder, - { - self.queries.on_disk_cache.serialize(self, encoder) - } - - /// If `true`, we should use the MIR-based borrowck, but also - /// fall back on the AST borrowck if the MIR-based one errors. - pub fn migrate_borrowck(self) -> bool { - self.borrowck_mode().migrate() - } - - /// What mode(s) of borrowck should we run? AST? MIR? both? - /// (Also considers the `#![feature(nll)]` setting.) - pub fn borrowck_mode(&self) -> BorrowckMode { - // Here are the main constraints we need to deal with: - // - // 1. An opts.borrowck_mode of `BorrowckMode::Migrate` is - // synonymous with no `-Z borrowck=...` flag at all. - // - // 2. We want to allow developers on the Nightly channel - // to opt back into the "hard error" mode for NLL, - // (which they can do via specifying `#![feature(nll)]` - // explicitly in their crate). - // - // So, this precedence list is how pnkfelix chose to work with - // the above constraints: - // - // * `#![feature(nll)]` *always* means use NLL with hard - // errors. (To simplify the code here, it now even overrides - // a user's attempt to specify `-Z borrowck=compare`, which - // we arguably do not need anymore and should remove.) - // - // * Otherwise, if no `-Z borrowck=...` then use migrate mode - // - // * Otherwise, use the behavior requested via `-Z borrowck=...` - - if self.features().nll { - return BorrowckMode::Mir; - } - - self.sess.opts.borrowck_mode - } - - #[inline] - pub fn local_crate_exports_generics(self) -> bool { - debug_assert!(self.sess.opts.share_generics()); - - self.sess.crate_types.borrow().iter().any(|crate_type| { - match crate_type { - CrateType::Executable - | CrateType::Staticlib - | CrateType::ProcMacro - | CrateType::Cdylib => false, - - // FIXME rust-lang/rust#64319, rust-lang/rust#64872: - // We want to block export of generics from dylibs, - // but we must fix rust-lang/rust#65890 before we can - // do that robustly. - CrateType::Dylib => true, - - CrateType::Rlib => true, - } - }) - } - - // Returns the `DefId` and the `BoundRegion` corresponding to the given region. - pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> { - let (suitable_region_binding_scope, bound_region) = match *region { - ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), - ty::ReEarlyBound(ref ebr) => { - (self.parent(ebr.def_id).unwrap(), ty::BoundRegion::BrNamed(ebr.def_id, ebr.name)) - } - _ => return None, // not a free region - }; - - let hir_id = self.hir().as_local_hir_id(suitable_region_binding_scope).unwrap(); - let is_impl_item = match self.hir().find(hir_id) { - Some(Node::Item(..)) | Some(Node::TraitItem(..)) => false, - Some(Node::ImplItem(..)) => { - self.is_bound_region_in_impl_item(suitable_region_binding_scope) - } - _ => return None, - }; - - return Some(FreeRegionInfo { - def_id: suitable_region_binding_scope, - boundregion: bound_region, - is_impl_item, - }); - } - - pub fn return_type_impl_trait(&self, scope_def_id: DefId) -> Option<(Ty<'tcx>, Span)> { - // HACK: `type_of_def_id()` will fail on these (#55796), so return `None`. - let hir_id = self.hir().as_local_hir_id(scope_def_id).unwrap(); - match self.hir().get(hir_id) { - Node::Item(item) => { - match item.kind { - ItemKind::Fn(..) => { /* `type_of_def_id()` will work */ } - _ => { - return None; - } - } - } - _ => { /* `type_of_def_id()` will work or panic */ } - } - - let ret_ty = self.type_of(scope_def_id); - match ret_ty.kind { - ty::FnDef(_, _) => { - let sig = ret_ty.fn_sig(*self); - let output = self.erase_late_bound_regions(&sig.output()); - if output.is_impl_trait() { - let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap(); - Some((output, fn_decl.output.span())) - } else { - None - } - } - _ => None, - } - } - - // Checks if the bound region is in Impl Item. - pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: DefId) -> bool { - let container_id = self.associated_item(suitable_region_binding_scope).container.id(); - if self.impl_trait_ref(container_id).is_some() { - // For now, we do not try to target impls of traits. This is - // because this message is going to suggest that the user - // change the fn signature, but they may not be free to do so, - // since the signature must match the trait. - // - // FIXME(#42706) -- in some cases, we could do better here. - return true; - } - false - } - - /// Determines whether identifiers in the assembly have strict naming rules. - /// Currently, only NVPTX* targets need it. - pub fn has_strict_asm_symbol_naming(&self) -> bool { - self.sess.target.target.arch.contains("nvptx") - } - - /// Returns `&'static core::panic::Location<'static>`. - pub fn caller_location_ty(&self) -> Ty<'tcx> { - self.mk_imm_ref( - self.lifetimes.re_static, - self.type_of(self.require_lang_item(PanicLocationLangItem, None)) - .subst(*self, self.mk_substs([self.lifetimes.re_static.into()].iter())), - ) - } - - /// Returns a displayable description and article for the given `def_id` (e.g. `("a", "struct")`). - pub fn article_and_description(&self, def_id: DefId) -> (&'static str, &'static str) { - match self.def_key(def_id).disambiguated_data.data { - DefPathData::TypeNs(..) | DefPathData::ValueNs(..) | DefPathData::MacroNs(..) => { - let kind = self.def_kind(def_id).unwrap(); - (kind.article(), kind.descr(def_id)) - } - DefPathData::ClosureExpr => match self.generator_kind(def_id) { - None => ("a", "closure"), - Some(rustc_hir::GeneratorKind::Async(..)) => ("an", "async closure"), - Some(rustc_hir::GeneratorKind::Gen) => ("a", "generator"), - }, - DefPathData::LifetimeNs(..) => ("a", "lifetime"), - DefPathData::Impl => ("an", "implementation"), - _ => bug!("article_and_description called on def_id {:?}", def_id), - } - } -} - -impl<'tcx> GlobalCtxt<'tcx> { - /// Calls the closure with a local `TyCtxt` using the given arena. - /// `interners` is a slot passed so we can create a CtxtInterners - /// with the same lifetime as `arena`. - pub fn enter_local<F, R>(&'tcx self, f: F) -> R - where - F: FnOnce(TyCtxt<'tcx>) -> R, - { - let tcx = TyCtxt { gcx: self }; - ty::tls::with_related_context(tcx, |icx| { - let new_icx = ty::tls::ImplicitCtxt { - tcx, - query: icx.query, - diagnostics: icx.diagnostics, - layout_depth: icx.layout_depth, - task_deps: icx.task_deps, - }; - ty::tls::enter_context(&new_icx, |_| f(tcx)) - }) - } -} - -/// A trait implemented for all `X<'a>` types that can be safely and -/// efficiently converted to `X<'tcx>` as long as they are part of the -/// provided `TyCtxt<'tcx>`. -/// This can be done, for example, for `Ty<'tcx>` or `SubstsRef<'tcx>` -/// by looking them up in their respective interners. -/// -/// However, this is still not the best implementation as it does -/// need to compare the components, even for interned values. -/// It would be more efficient if `TypedArena` provided a way to -/// determine whether the address is in the allocated range. -/// -/// `None` is returned if the value or one of the components is not part -/// of the provided context. -/// For `Ty`, `None` can be returned if either the type interner doesn't -/// contain the `TyKind` key or if the address of the interned -/// pointer differs. The latter case is possible if a primitive type, -/// e.g., `()` or `u8`, was interned in a different context. -pub trait Lift<'tcx>: fmt::Debug { - type Lifted: fmt::Debug + 'tcx; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted>; -} - -macro_rules! nop_lift { - ($set:ident; $ty:ty => $lifted:ty) => { - impl<'a, 'tcx> Lift<'tcx> for $ty { - type Lifted = $lifted; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - if tcx.interners.$set.contains_pointer_to(&Interned(*self)) { - Some(unsafe { mem::transmute(*self) }) - } else { - None - } - } - } - }; -} - -macro_rules! nop_list_lift { - ($set:ident; $ty:ty => $lifted:ty) => { - impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> { - type Lifted = &'tcx List<$lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - if self.is_empty() { - return Some(List::empty()); - } - if tcx.interners.$set.contains_pointer_to(&Interned(*self)) { - Some(unsafe { mem::transmute(*self) }) - } else { - None - } - } - } - }; -} - -nop_lift! {type_; Ty<'a> => Ty<'tcx>} -nop_lift! {region; Region<'a> => Region<'tcx>} -nop_lift! {goal; Goal<'a> => Goal<'tcx>} -nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>} - -nop_list_lift! {goal_list; Goal<'a> => Goal<'tcx>} -nop_list_lift! {clauses; Clause<'a> => Clause<'tcx>} -nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} -nop_list_lift! {existential_predicates; ExistentialPredicate<'a> => ExistentialPredicate<'tcx>} -nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>} -nop_list_lift! {canonical_var_infos; CanonicalVarInfo => CanonicalVarInfo} -nop_list_lift! {projs; ProjectionKind => ProjectionKind} - -// This is the impl for `&'a InternalSubsts<'a>`. -nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>} - -pub mod tls { - use super::{ptr_eq, GlobalCtxt, TyCtxt}; - - use crate::dep_graph::TaskDeps; - use crate::ty::query; - use rustc_data_structures::sync::{self, Lock}; - use rustc_data_structures::thin_vec::ThinVec; - use rustc_data_structures::OnDrop; - use rustc_errors::Diagnostic; - use std::mem; - - #[cfg(not(parallel_compiler))] - use std::cell::Cell; - - #[cfg(parallel_compiler)] - use rustc_rayon_core as rayon_core; - - /// This is the implicit state of rustc. It contains the current - /// `TyCtxt` and query. It is updated when creating a local interner or - /// executing a new query. Whenever there's a `TyCtxt` value available - /// you should also have access to an `ImplicitCtxt` through the functions - /// in this module. - #[derive(Clone)] - pub struct ImplicitCtxt<'a, 'tcx> { - /// The current `TyCtxt`. Initially created by `enter_global` and updated - /// by `enter_local` with a new local interner. - pub tcx: TyCtxt<'tcx>, - - /// The current query job, if any. This is updated by `JobOwner::start` in - /// `ty::query::plumbing` when executing a query. - pub query: Option<query::QueryJobId>, - - /// Where to store diagnostics for the current query job, if any. - /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. - pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>, - - /// Used to prevent layout from recursing too deeply. - pub layout_depth: usize, - - /// The current dep graph task. This is used to add dependencies to queries - /// when executing them. - pub task_deps: Option<&'a Lock<TaskDeps>>, - } - - /// Sets Rayon's thread-local variable, which is preserved for Rayon jobs - /// to `value` during the call to `f`. It is restored to its previous value after. - /// This is used to set the pointer to the new `ImplicitCtxt`. - #[cfg(parallel_compiler)] - #[inline] - fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R { - rayon_core::tlv::with(value, f) - } - - /// Gets Rayon's thread-local variable, which is preserved for Rayon jobs. - /// This is used to get the pointer to the current `ImplicitCtxt`. - #[cfg(parallel_compiler)] - #[inline] - fn get_tlv() -> usize { - rayon_core::tlv::get() - } - - #[cfg(not(parallel_compiler))] - thread_local! { - /// A thread local variable that stores a pointer to the current `ImplicitCtxt`. - static TLV: Cell<usize> = Cell::new(0); - } - - /// Sets TLV to `value` during the call to `f`. - /// It is restored to its previous value after. - /// This is used to set the pointer to the new `ImplicitCtxt`. - #[cfg(not(parallel_compiler))] - #[inline] - fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R { - let old = get_tlv(); - let _reset = OnDrop(move || TLV.with(|tlv| tlv.set(old))); - TLV.with(|tlv| tlv.set(value)); - f() - } - - /// Gets the pointer to the current `ImplicitCtxt`. - #[cfg(not(parallel_compiler))] - #[inline] - fn get_tlv() -> usize { - TLV.with(|tlv| tlv.get()) - } - - /// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`. - #[inline] - pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R - where - F: FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R, - { - set_tlv(context as *const _ as usize, || f(&context)) - } - - /// Enters `GlobalCtxt` by setting up libsyntax callbacks and - /// creating a initial `TyCtxt` and `ImplicitCtxt`. - /// This happens once per rustc session and `TyCtxt`s only exists - /// inside the `f` function. - pub fn enter_global<'tcx, F, R>(gcx: &'tcx GlobalCtxt<'tcx>, f: F) -> R - where - F: FnOnce(TyCtxt<'tcx>) -> R, - { - // Update `GCX_PTR` to indicate there's a `GlobalCtxt` available. - GCX_PTR.with(|lock| { - *lock.lock() = gcx as *const _ as usize; - }); - // Set `GCX_PTR` back to 0 when we exit. - let _on_drop = OnDrop(move || { - GCX_PTR.with(|lock| *lock.lock() = 0); - }); - - let tcx = TyCtxt { gcx }; - let icx = - ImplicitCtxt { tcx, query: None, diagnostics: None, layout_depth: 0, task_deps: None }; - enter_context(&icx, |_| f(tcx)) - } - - scoped_thread_local! { - /// Stores a pointer to the `GlobalCtxt` if one is available. - /// This is used to access the `GlobalCtxt` in the deadlock handler given to Rayon. - pub static GCX_PTR: Lock<usize> - } - - /// Creates a `TyCtxt` and `ImplicitCtxt` based on the `GCX_PTR` thread local. - /// This is used in the deadlock handler. - pub unsafe fn with_global<F, R>(f: F) -> R - where - F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R, - { - let gcx = GCX_PTR.with(|lock| *lock.lock()); - assert!(gcx != 0); - let gcx = &*(gcx as *const GlobalCtxt<'_>); - let tcx = TyCtxt { gcx }; - let icx = - ImplicitCtxt { query: None, diagnostics: None, tcx, layout_depth: 0, task_deps: None }; - enter_context(&icx, |_| f(tcx)) - } - - /// Allows access to the current `ImplicitCtxt` in a closure if one is available. - #[inline] - pub fn with_context_opt<F, R>(f: F) -> R - where - F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R, - { - let context = get_tlv(); - if context == 0 { - f(None) - } else { - // We could get a `ImplicitCtxt` pointer from another thread. - // Ensure that `ImplicitCtxt` is `Sync`. - sync::assert_sync::<ImplicitCtxt<'_, '_>>(); - - unsafe { f(Some(&*(context as *const ImplicitCtxt<'_, '_>))) } - } - } - - /// Allows access to the current `ImplicitCtxt`. - /// Panics if there is no `ImplicitCtxt` available. - #[inline] - pub fn with_context<F, R>(f: F) -> R - where - F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R, - { - with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls"))) - } - - /// Allows access to the current `ImplicitCtxt` whose tcx field has the same global - /// interner as the tcx argument passed in. This means the closure is given an `ImplicitCtxt` - /// with the same `'tcx` lifetime as the `TyCtxt` passed in. - /// This will panic if you pass it a `TyCtxt` which has a different global interner from - /// the current `ImplicitCtxt`'s `tcx` field. - #[inline] - pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R - where - F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R, - { - with_context(|context| unsafe { - assert!(ptr_eq(context.tcx.gcx, tcx.gcx)); - let context: &ImplicitCtxt<'_, '_> = mem::transmute(context); - f(context) - }) - } - - /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. - /// Panics if there is no `ImplicitCtxt` available. - #[inline] - pub fn with<F, R>(f: F) -> R - where - F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R, - { - with_context(|context| f(context.tcx)) - } - - /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. - /// The closure is passed None if there is no `ImplicitCtxt` available. - #[inline] - pub fn with_opt<F, R>(f: F) -> R - where - F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R, - { - with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx))) - } -} - -macro_rules! sty_debug_print { - ($ctxt: expr, $($variant: ident),*) => {{ - // Curious inner module to allow variant names to be used as - // variable names. - #[allow(non_snake_case)] - mod inner { - use crate::ty::{self, TyCtxt}; - use crate::ty::context::Interned; - - #[derive(Copy, Clone)] - struct DebugStat { - total: usize, - lt_infer: usize, - ty_infer: usize, - ct_infer: usize, - all_infer: usize, - } - - pub fn go(tcx: TyCtxt<'_>) { - let mut total = DebugStat { - total: 0, - lt_infer: 0, - ty_infer: 0, - ct_infer: 0, - all_infer: 0, - }; - $(let mut $variant = total;)* - - let shards = tcx.interners.type_.lock_shards(); - let types = shards.iter().flat_map(|shard| shard.keys()); - for &Interned(t) in types { - let variant = match t.kind { - ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | - ty::Float(..) | ty::Str | ty::Never => continue, - ty::Error => /* unimportant */ continue, - $(ty::$variant(..) => &mut $variant,)* - }; - let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER); - let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER); - let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER); - - variant.total += 1; - total.total += 1; - if lt { total.lt_infer += 1; variant.lt_infer += 1 } - if ty { total.ty_infer += 1; variant.ty_infer += 1 } - if ct { total.ct_infer += 1; variant.ct_infer += 1 } - if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 } - } - println!("Ty interner total ty lt ct all"); - $(println!(" {:18}: {uses:6} {usespc:4.1}%, \ - {ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%", - stringify!($variant), - uses = $variant.total, - usespc = $variant.total as f64 * 100.0 / total.total as f64, - ty = $variant.ty_infer as f64 * 100.0 / total.total as f64, - lt = $variant.lt_infer as f64 * 100.0 / total.total as f64, - ct = $variant.ct_infer as f64 * 100.0 / total.total as f64, - all = $variant.all_infer as f64 * 100.0 / total.total as f64); - )* - println!(" total {uses:6} \ - {ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%", - uses = total.total, - ty = total.ty_infer as f64 * 100.0 / total.total as f64, - lt = total.lt_infer as f64 * 100.0 / total.total as f64, - ct = total.ct_infer as f64 * 100.0 / total.total as f64, - all = total.all_infer as f64 * 100.0 / total.total as f64) - } - } - - inner::go($ctxt) - }} -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn print_debug_stats(self) { - sty_debug_print!( - self, - Adt, - Array, - Slice, - RawPtr, - Ref, - FnDef, - FnPtr, - Placeholder, - Generator, - GeneratorWitness, - Dynamic, - Closure, - Tuple, - Bound, - Param, - Infer, - UnnormalizedProjection, - Projection, - Opaque, - Foreign - ); - - println!("InternalSubsts interner: #{}", self.interners.substs.len()); - println!("Region interner: #{}", self.interners.region.len()); - println!("Stability interner: #{}", self.stability_interner.len()); - println!("Const Stability interner: #{}", self.const_stability_interner.len()); - println!("Allocation interner: #{}", self.allocation_interner.len()); - println!("Layout interner: #{}", self.layout_interner.len()); - } -} - -/// An entry in an interner. -struct Interned<'tcx, T: ?Sized>(&'tcx T); - -impl<'tcx, T: 'tcx + ?Sized> Clone for Interned<'tcx, T> { - fn clone(&self) -> Self { - Interned(self.0) - } -} -impl<'tcx, T: 'tcx + ?Sized> Copy for Interned<'tcx, T> {} - -impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> { - fn into_pointer(&self) -> *const () { - self.0 as *const _ as *const () - } -} -// N.B., an `Interned<Ty>` compares and hashes as a `TyKind`. -impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> { - fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool { - self.0.kind == other.0.kind - } -} - -impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {} - -impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> { - fn hash<H: Hasher>(&self, s: &mut H) { - self.0.kind.hash(s) - } -} - -#[allow(rustc::usage_of_ty_tykind)] -impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> { - fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> { - &self.0.kind - } -} - -// N.B., an `Interned<List<T>>` compares and hashes as its elements. -impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> { - fn eq(&self, other: &Interned<'tcx, List<T>>) -> bool { - self.0[..] == other.0[..] - } -} - -impl<'tcx, T: Eq> Eq for Interned<'tcx, List<T>> {} - -impl<'tcx, T: Hash> Hash for Interned<'tcx, List<T>> { - fn hash<H: Hasher>(&self, s: &mut H) { - self.0[..].hash(s) - } -} - -impl<'tcx> Borrow<[Ty<'tcx>]> for Interned<'tcx, List<Ty<'tcx>>> { - fn borrow<'a>(&'a self) -> &'a [Ty<'tcx>] { - &self.0[..] - } -} - -impl<'tcx> Borrow<[CanonicalVarInfo]> for Interned<'tcx, List<CanonicalVarInfo>> { - fn borrow(&self) -> &[CanonicalVarInfo] { - &self.0[..] - } -} - -impl<'tcx> Borrow<[GenericArg<'tcx>]> for Interned<'tcx, InternalSubsts<'tcx>> { - fn borrow<'a>(&'a self) -> &'a [GenericArg<'tcx>] { - &self.0[..] - } -} - -impl<'tcx> Borrow<[ProjectionKind]> for Interned<'tcx, List<ProjectionKind>> { - fn borrow(&self) -> &[ProjectionKind] { - &self.0[..] - } -} - -impl<'tcx> Borrow<[PlaceElem<'tcx>]> for Interned<'tcx, List<PlaceElem<'tcx>>> { - fn borrow(&self) -> &[PlaceElem<'tcx>] { - &self.0[..] - } -} - -impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> { - fn borrow(&self) -> &RegionKind { - &self.0 - } -} - -impl<'tcx> Borrow<GoalKind<'tcx>> for Interned<'tcx, GoalKind<'tcx>> { - fn borrow<'a>(&'a self) -> &'a GoalKind<'tcx> { - &self.0 - } -} - -impl<'tcx> Borrow<[ExistentialPredicate<'tcx>]> - for Interned<'tcx, List<ExistentialPredicate<'tcx>>> -{ - fn borrow<'a>(&'a self) -> &'a [ExistentialPredicate<'tcx>] { - &self.0[..] - } -} - -impl<'tcx> Borrow<[Predicate<'tcx>]> for Interned<'tcx, List<Predicate<'tcx>>> { - fn borrow<'a>(&'a self) -> &'a [Predicate<'tcx>] { - &self.0[..] - } -} - -impl<'tcx> Borrow<Const<'tcx>> for Interned<'tcx, Const<'tcx>> { - fn borrow<'a>(&'a self) -> &'a Const<'tcx> { - &self.0 - } -} - -impl<'tcx> Borrow<[Clause<'tcx>]> for Interned<'tcx, List<Clause<'tcx>>> { - fn borrow<'a>(&'a self) -> &'a [Clause<'tcx>] { - &self.0[..] - } -} - -impl<'tcx> Borrow<[Goal<'tcx>]> for Interned<'tcx, List<Goal<'tcx>>> { - fn borrow<'a>(&'a self) -> &'a [Goal<'tcx>] { - &self.0[..] - } -} - -macro_rules! direct_interners { - ($($name:ident: $method:ident($ty:ty)),+) => { - $(impl<'tcx> PartialEq for Interned<'tcx, $ty> { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - - impl<'tcx> Eq for Interned<'tcx, $ty> {} - - impl<'tcx> Hash for Interned<'tcx, $ty> { - fn hash<H: Hasher>(&self, s: &mut H) { - self.0.hash(s) - } - } - - impl<'tcx> TyCtxt<'tcx> { - pub fn $method(self, v: $ty) -> &'tcx $ty { - self.interners.$name.intern_ref(&v, || { - Interned(self.interners.arena.alloc(v)) - }).0 - } - })+ - } -} - -pub fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { - x.has_type_flags(ty::TypeFlags::KEEP_IN_LOCAL_TCX) -} - -direct_interners!( - region: mk_region(RegionKind), - goal: mk_goal(GoalKind<'tcx>), - const_: mk_const(Const<'tcx>) -); - -macro_rules! slice_interners { - ($($field:ident: $method:ident($ty:ty)),+) => ( - $(impl<'tcx> TyCtxt<'tcx> { - pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> { - self.interners.$field.intern_ref(v, || { - Interned(List::from_arena(&*self.arena, v)) - }).0 - } - })+ - ); -} - -slice_interners!( - type_list: _intern_type_list(Ty<'tcx>), - substs: _intern_substs(GenericArg<'tcx>), - canonical_var_infos: _intern_canonical_var_infos(CanonicalVarInfo), - existential_predicates: _intern_existential_predicates(ExistentialPredicate<'tcx>), - predicates: _intern_predicates(Predicate<'tcx>), - clauses: _intern_clauses(Clause<'tcx>), - goal_list: _intern_goals(Goal<'tcx>), - projs: _intern_projs(ProjectionKind), - place_elems: _intern_place_elems(PlaceElem<'tcx>) -); - -impl<'tcx> TyCtxt<'tcx> { - /// Given a `fn` type, returns an equivalent `unsafe fn` type; - /// that is, a `fn` type that is equivalent in every way for being - /// unsafe. - pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> { - assert_eq!(sig.unsafety(), hir::Unsafety::Normal); - self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig })) - } - - /// Given a closure signature `sig`, returns an equivalent `fn` - /// type with the same signature. Detuples and so forth -- so - /// e.g., if we have a sig with `Fn<(u32, i32)>` then you would get - /// a `fn(u32, i32)`. - /// `unsafety` determines the unsafety of the `fn` type. If you pass - /// `hir::Unsafety::Unsafe` in the previous example, then you would get - /// an `unsafe fn (u32, i32)`. - /// It cannot convert a closure that requires unsafe. - pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>, unsafety: hir::Unsafety) -> Ty<'tcx> { - let converted_sig = sig.map_bound(|s| { - let params_iter = match s.inputs()[0].kind { - ty::Tuple(params) => params.into_iter().map(|k| k.expect_ty()), - _ => bug!(), - }; - self.mk_fn_sig(params_iter, s.output(), s.c_variadic, unsafety, abi::Abi::Rust) - }); - - self.mk_fn_ptr(converted_sig) - } - - #[allow(rustc::usage_of_ty_tykind)] - #[inline] - pub fn mk_ty(&self, st: TyKind<'tcx>) -> Ty<'tcx> { - self.interners.intern_ty(st) - } - - pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> { - match tm { - ast::IntTy::Isize => self.types.isize, - ast::IntTy::I8 => self.types.i8, - ast::IntTy::I16 => self.types.i16, - ast::IntTy::I32 => self.types.i32, - ast::IntTy::I64 => self.types.i64, - ast::IntTy::I128 => self.types.i128, - } - } - - pub fn mk_mach_uint(self, tm: ast::UintTy) -> Ty<'tcx> { - match tm { - ast::UintTy::Usize => self.types.usize, - ast::UintTy::U8 => self.types.u8, - ast::UintTy::U16 => self.types.u16, - ast::UintTy::U32 => self.types.u32, - ast::UintTy::U64 => self.types.u64, - ast::UintTy::U128 => self.types.u128, - } - } - - pub fn mk_mach_float(self, tm: ast::FloatTy) -> Ty<'tcx> { - match tm { - ast::FloatTy::F32 => self.types.f32, - ast::FloatTy::F64 => self.types.f64, - } - } - - #[inline] - pub fn mk_str(self) -> Ty<'tcx> { - self.mk_ty(Str) - } - - #[inline] - pub fn mk_static_str(self) -> Ty<'tcx> { - self.mk_imm_ref(self.lifetimes.re_static, self.mk_str()) - } - - #[inline] - pub fn mk_adt(self, def: &'tcx AdtDef, substs: SubstsRef<'tcx>) -> Ty<'tcx> { - // Take a copy of substs so that we own the vectors inside. - self.mk_ty(Adt(def, substs)) - } - - #[inline] - pub fn mk_foreign(self, def_id: DefId) -> Ty<'tcx> { - self.mk_ty(Foreign(def_id)) - } - - fn mk_generic_adt(self, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> { - let adt_def = self.adt_def(wrapper_def_id); - let substs = - InternalSubsts::for_item(self, wrapper_def_id, |param, substs| match param.kind { - GenericParamDefKind::Lifetime | GenericParamDefKind::Const => bug!(), - GenericParamDefKind::Type { has_default, .. } => { - if param.index == 0 { - ty_param.into() - } else { - assert!(has_default); - self.type_of(param.def_id).subst(self, substs).into() - } - } - }); - self.mk_ty(Adt(adt_def, substs)) - } - - #[inline] - pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem, None); - self.mk_generic_adt(def_id, ty) - } - - #[inline] - pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem) -> Option<Ty<'tcx>> { - let def_id = self.lang_items().require(item).ok()?; - Some(self.mk_generic_adt(def_id, ty)) - } - - #[inline] - pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None); - self.mk_generic_adt(def_id, ty) - } - - #[inline] - pub fn mk_ptr(self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { - self.mk_ty(RawPtr(tm)) - } - - #[inline] - pub fn mk_ref(self, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { - self.mk_ty(Ref(r, tm.ty, tm.mutbl)) - } - - #[inline] - pub fn mk_mut_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ref(r, TypeAndMut { ty: ty, mutbl: hir::Mutability::Mut }) - } - - #[inline] - pub fn mk_imm_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ref(r, TypeAndMut { ty: ty, mutbl: hir::Mutability::Not }) - } - - #[inline] - pub fn mk_mut_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ptr(TypeAndMut { ty: ty, mutbl: hir::Mutability::Mut }) - } - - #[inline] - pub fn mk_imm_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ptr(TypeAndMut { ty: ty, mutbl: hir::Mutability::Not }) - } - - #[inline] - pub fn mk_nil_ptr(self) -> Ty<'tcx> { - self.mk_imm_ptr(self.mk_unit()) - } - - #[inline] - pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - self.mk_ty(Array(ty, ty::Const::from_usize(self, n))) - } - - #[inline] - pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ty(Slice(ty)) - } - - #[inline] - pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> { - let kinds: Vec<_> = ts.into_iter().map(|&t| GenericArg::from(t)).collect(); - self.mk_ty(Tuple(self.intern_substs(&kinds))) - } - - pub fn mk_tup<I: InternAs<[Ty<'tcx>], Ty<'tcx>>>(self, iter: I) -> I::Output { - iter.intern_with(|ts| { - let kinds: Vec<_> = ts.into_iter().map(|&t| GenericArg::from(t)).collect(); - self.mk_ty(Tuple(self.intern_substs(&kinds))) - }) - } - - #[inline] - pub fn mk_unit(self) -> Ty<'tcx> { - self.types.unit - } - - #[inline] - pub fn mk_diverging_default(self) -> Ty<'tcx> { - if self.features().never_type_fallback { self.types.never } else { self.types.unit } - } - - #[inline] - pub fn mk_bool(self) -> Ty<'tcx> { - self.mk_ty(Bool) - } - - #[inline] - pub fn mk_fn_def(self, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> { - self.mk_ty(FnDef(def_id, substs)) - } - - #[inline] - pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> { - self.mk_ty(FnPtr(fty)) - } - - #[inline] - pub fn mk_dynamic( - self, - obj: ty::Binder<&'tcx List<ExistentialPredicate<'tcx>>>, - reg: ty::Region<'tcx>, - ) -> Ty<'tcx> { - self.mk_ty(Dynamic(obj, reg)) - } - - #[inline] - pub fn mk_projection(self, item_def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> { - self.mk_ty(Projection(ProjectionTy { item_def_id, substs })) - } - - #[inline] - pub fn mk_closure(self, closure_id: DefId, closure_substs: SubstsRef<'tcx>) -> Ty<'tcx> { - self.mk_ty(Closure(closure_id, closure_substs)) - } - - #[inline] - pub fn mk_generator( - self, - id: DefId, - generator_substs: SubstsRef<'tcx>, - movability: hir::Movability, - ) -> Ty<'tcx> { - self.mk_ty(Generator(id, generator_substs, movability)) - } - - #[inline] - pub fn mk_generator_witness(self, types: ty::Binder<&'tcx List<Ty<'tcx>>>) -> Ty<'tcx> { - self.mk_ty(GeneratorWitness(types)) - } - - #[inline] - pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> { - self.mk_ty_infer(TyVar(v)) - } - - #[inline] - pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> &'tcx Const<'tcx> { - self.mk_const(ty::Const { val: ty::ConstKind::Infer(InferConst::Var(v)), ty }) - } - - #[inline] - pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> { - self.mk_ty_infer(IntVar(v)) - } - - #[inline] - pub fn mk_float_var(self, v: FloatVid) -> Ty<'tcx> { - self.mk_ty_infer(FloatVar(v)) - } - - #[inline] - pub fn mk_ty_infer(self, it: InferTy) -> Ty<'tcx> { - self.mk_ty(Infer(it)) - } - - #[inline] - pub fn mk_const_infer(self, ic: InferConst<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> { - self.mk_const(ty::Const { val: ty::ConstKind::Infer(ic), ty }) - } - - #[inline] - pub fn mk_ty_param(self, index: u32, name: Symbol) -> Ty<'tcx> { - self.mk_ty(Param(ParamTy { index, name: name })) - } - - #[inline] - pub fn mk_const_param(self, index: u32, name: Symbol, ty: Ty<'tcx>) -> &'tcx Const<'tcx> { - self.mk_const(ty::Const { val: ty::ConstKind::Param(ParamConst { index, name }), ty }) - } - - pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { - match param.kind { - GenericParamDefKind::Lifetime => { - self.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())).into() - } - GenericParamDefKind::Type { .. } => self.mk_ty_param(param.index, param.name).into(), - GenericParamDefKind::Const => { - self.mk_const_param(param.index, param.name, self.type_of(param.def_id)).into() - } - } - } - - #[inline] - pub fn mk_opaque(self, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> { - self.mk_ty(Opaque(def_id, substs)) - } - - pub fn mk_place_field(self, place: Place<'tcx>, f: Field, ty: Ty<'tcx>) -> Place<'tcx> { - self.mk_place_elem(place, PlaceElem::Field(f, ty)) - } - - pub fn mk_place_deref(self, place: Place<'tcx>) -> Place<'tcx> { - self.mk_place_elem(place, PlaceElem::Deref) - } - - pub fn mk_place_downcast( - self, - place: Place<'tcx>, - adt_def: &'tcx AdtDef, - variant_index: VariantIdx, - ) -> Place<'tcx> { - self.mk_place_elem( - place, - PlaceElem::Downcast(Some(adt_def.variants[variant_index].ident.name), variant_index), - ) - } - - pub fn mk_place_downcast_unnamed( - self, - place: Place<'tcx>, - variant_index: VariantIdx, - ) -> Place<'tcx> { - self.mk_place_elem(place, PlaceElem::Downcast(None, variant_index)) - } - - pub fn mk_place_index(self, place: Place<'tcx>, index: Local) -> Place<'tcx> { - self.mk_place_elem(place, PlaceElem::Index(index)) - } - - /// This method copies `Place`'s projection, add an element and reintern it. Should not be used - /// to build a full `Place` it's just a convenient way to grab a projection and modify it in - /// flight. - pub fn mk_place_elem(self, place: Place<'tcx>, elem: PlaceElem<'tcx>) -> Place<'tcx> { - let mut projection = place.projection.to_vec(); - projection.push(elem); - - Place { local: place.local, projection: self.intern_place_elems(&projection) } - } - - pub fn intern_existential_predicates( - self, - eps: &[ExistentialPredicate<'tcx>], - ) -> &'tcx List<ExistentialPredicate<'tcx>> { - assert!(!eps.is_empty()); - assert!(eps.windows(2).all(|w| w[0].stable_cmp(self, &w[1]) != Ordering::Greater)); - self._intern_existential_predicates(eps) - } - - pub fn intern_predicates(self, preds: &[Predicate<'tcx>]) -> &'tcx List<Predicate<'tcx>> { - // FIXME consider asking the input slice to be sorted to avoid - // re-interning permutations, in which case that would be asserted - // here. - if preds.len() == 0 { - // The macro-generated method below asserts we don't intern an empty slice. - List::empty() - } else { - self._intern_predicates(preds) - } - } - - pub fn intern_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx List<Ty<'tcx>> { - if ts.len() == 0 { List::empty() } else { self._intern_type_list(ts) } - } - - pub fn intern_substs(self, ts: &[GenericArg<'tcx>]) -> &'tcx List<GenericArg<'tcx>> { - if ts.len() == 0 { List::empty() } else { self._intern_substs(ts) } - } - - pub fn intern_projs(self, ps: &[ProjectionKind]) -> &'tcx List<ProjectionKind> { - if ps.len() == 0 { List::empty() } else { self._intern_projs(ps) } - } - - pub fn intern_place_elems(self, ts: &[PlaceElem<'tcx>]) -> &'tcx List<PlaceElem<'tcx>> { - if ts.len() == 0 { List::empty() } else { self._intern_place_elems(ts) } - } - - pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVarInfos<'tcx> { - if ts.len() == 0 { List::empty() } else { self._intern_canonical_var_infos(ts) } - } - - pub fn intern_clauses(self, ts: &[Clause<'tcx>]) -> Clauses<'tcx> { - if ts.len() == 0 { List::empty() } else { self._intern_clauses(ts) } - } - - pub fn intern_goals(self, ts: &[Goal<'tcx>]) -> Goals<'tcx> { - if ts.len() == 0 { List::empty() } else { self._intern_goals(ts) } - } - - pub fn mk_fn_sig<I>( - self, - inputs: I, - output: I::Item, - c_variadic: bool, - unsafety: hir::Unsafety, - abi: abi::Abi, - ) -> <I::Item as InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>>::Output - where - I: Iterator<Item: InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>>, - { - inputs.chain(iter::once(output)).intern_with(|xs| ty::FnSig { - inputs_and_output: self.intern_type_list(xs), - c_variadic, - unsafety, - abi, - }) - } - - pub fn mk_existential_predicates< - I: InternAs<[ExistentialPredicate<'tcx>], &'tcx List<ExistentialPredicate<'tcx>>>, - >( - self, - iter: I, - ) -> I::Output { - iter.intern_with(|xs| self.intern_existential_predicates(xs)) - } - - pub fn mk_predicates<I: InternAs<[Predicate<'tcx>], &'tcx List<Predicate<'tcx>>>>( - self, - iter: I, - ) -> I::Output { - iter.intern_with(|xs| self.intern_predicates(xs)) - } - - pub fn mk_type_list<I: InternAs<[Ty<'tcx>], &'tcx List<Ty<'tcx>>>>(self, iter: I) -> I::Output { - iter.intern_with(|xs| self.intern_type_list(xs)) - } - - pub fn mk_substs<I: InternAs<[GenericArg<'tcx>], &'tcx List<GenericArg<'tcx>>>>( - self, - iter: I, - ) -> I::Output { - iter.intern_with(|xs| self.intern_substs(xs)) - } - - pub fn mk_place_elems<I: InternAs<[PlaceElem<'tcx>], &'tcx List<PlaceElem<'tcx>>>>( - self, - iter: I, - ) -> I::Output { - iter.intern_with(|xs| self.intern_place_elems(xs)) - } - - pub fn mk_substs_trait(self, self_ty: Ty<'tcx>, rest: &[GenericArg<'tcx>]) -> SubstsRef<'tcx> { - self.mk_substs(iter::once(self_ty.into()).chain(rest.iter().cloned())) - } - - pub fn mk_clauses<I: InternAs<[Clause<'tcx>], Clauses<'tcx>>>(self, iter: I) -> I::Output { - iter.intern_with(|xs| self.intern_clauses(xs)) - } - - pub fn mk_goals<I: InternAs<[Goal<'tcx>], Goals<'tcx>>>(self, iter: I) -> I::Output { - iter.intern_with(|xs| self.intern_goals(xs)) - } - - /// Walks upwards from `id` to find a node which might change lint levels with attributes. - /// It stops at `bound` and just returns it if reached. - pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId { - let hir = self.hir(); - loop { - if id == bound { - return bound; - } - - if hir.attrs(id).iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some()) { - return id; - } - let next = hir.get_parent_node(id); - if next == id { - bug!("lint traversal reached the root of the crate"); - } - id = next; - } - } - - pub fn lint_level_at_node( - self, - lint: &'static Lint, - mut id: hir::HirId, - ) -> (Level, LintSource) { - let sets = self.lint_levels(LOCAL_CRATE); - loop { - if let Some(pair) = sets.level_and_source(lint, id, self.sess) { - return pair; - } - let next = self.hir().get_parent_node(id); - if next == id { - bug!("lint traversal reached the root of the crate"); - } - id = next; - } - } - - pub fn struct_span_lint_hir( - self, - lint: &'static Lint, - hir_id: HirId, - span: impl Into<MultiSpan>, - decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>), - ) { - let (level, src) = self.lint_level_at_node(lint, hir_id); - struct_lint_level(self.sess, lint, level, src, Some(span.into()), decorate); - } - - pub fn struct_lint_node( - self, - lint: &'static Lint, - id: HirId, - decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>), - ) { - let (level, src) = self.lint_level_at_node(lint, id); - struct_lint_level(self.sess, lint, level, src, None, decorate); - } - - pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx StableVec<TraitCandidate>> { - self.in_scope_traits_map(id.owner).and_then(|map| map.get(&id.local_id)) - } - - pub fn named_region(self, id: HirId) -> Option<resolve_lifetime::Region> { - self.named_region_map(id.owner).and_then(|map| map.get(&id.local_id).cloned()) - } - - pub fn is_late_bound(self, id: HirId) -> bool { - self.is_late_bound_map(id.owner).map(|set| set.contains(&id.local_id)).unwrap_or(false) - } - - pub fn object_lifetime_defaults(self, id: HirId) -> Option<&'tcx [ObjectLifetimeDefault]> { - self.object_lifetime_defaults_map(id.owner) - .and_then(|map| map.get(&id.local_id).map(|v| &**v)) - } -} - -pub trait InternAs<T: ?Sized, R> { - type Output; - fn intern_with<F>(self, f: F) -> Self::Output - where - F: FnOnce(&T) -> R; -} - -impl<I, T, R, E> InternAs<[T], R> for I -where - E: InternIteratorElement<T, R>, - I: Iterator<Item = E>, -{ - type Output = E::Output; - fn intern_with<F>(self, f: F) -> Self::Output - where - F: FnOnce(&[T]) -> R, - { - E::intern_with(self, f) - } -} - -pub trait InternIteratorElement<T, R>: Sized { - type Output; - fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output; -} - -impl<T, R> InternIteratorElement<T, R> for T { - type Output = R; - fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { - f(&iter.collect::<SmallVec<[_; 8]>>()) - } -} - -impl<'a, T, R> InternIteratorElement<T, R> for &'a T -where - T: Clone + 'a, -{ - type Output = R; - fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { - f(&iter.cloned().collect::<SmallVec<[_; 8]>>()) - } -} - -impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> { - type Output = Result<R, E>; - fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>( - mut iter: I, - f: F, - ) -> Self::Output { - // This code is hot enough that it's worth specializing for the most - // common length lists, to avoid the overhead of `SmallVec` creation. - // The match arms are in order of frequency. The 1, 2, and 0 cases are - // typically hit in ~95% of cases. We assume that if the upper and - // lower bounds from `size_hint` agree they are correct. - Ok(match iter.size_hint() { - (1, Some(1)) => { - let t0 = iter.next().unwrap()?; - assert!(iter.next().is_none()); - f(&[t0]) - } - (2, Some(2)) => { - let t0 = iter.next().unwrap()?; - let t1 = iter.next().unwrap()?; - assert!(iter.next().is_none()); - f(&[t0, t1]) - } - (0, Some(0)) => { - assert!(iter.next().is_none()); - f(&[]) - } - _ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?), - }) - } -} - -// We are comparing types with different invariant lifetimes, so `ptr::eq` -// won't work for us. -fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool { - t as *const () == u as *const () -} - -pub fn provide(providers: &mut ty::query::Providers<'_>) { - providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id); - providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).map(|v| &v[..]); - providers.crate_name = |tcx, id| { - assert_eq!(id, LOCAL_CRATE); - tcx.crate_name - }; - providers.maybe_unused_trait_import = |tcx, id| tcx.maybe_unused_trait_imports.contains(&id); - providers.maybe_unused_extern_crates = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - &tcx.maybe_unused_extern_crates[..] - }; - providers.names_imported_by_glob_use = |tcx, id| { - assert_eq!(id.krate, LOCAL_CRATE); - Lrc::new(tcx.glob_map.get(&id).cloned().unwrap_or_default()) - }; - - providers.lookup_stability = |tcx, id| { - assert_eq!(id.krate, LOCAL_CRATE); - let id = tcx.hir().definitions().def_index_to_hir_id(id.index); - tcx.stability().local_stability(id) - }; - providers.lookup_const_stability = |tcx, id| { - assert_eq!(id.krate, LOCAL_CRATE); - let id = tcx.hir().definitions().def_index_to_hir_id(id.index); - tcx.stability().local_const_stability(id) - }; - providers.lookup_deprecation_entry = |tcx, id| { - assert_eq!(id.krate, LOCAL_CRATE); - let id = tcx.hir().definitions().def_index_to_hir_id(id.index); - tcx.stability().local_deprecation_entry(id) - }; - providers.extern_mod_stmt_cnum = |tcx, id| { - let id = tcx.hir().as_local_node_id(id).unwrap(); - tcx.extern_crate_map.get(&id).cloned() - }; - providers.all_crate_nums = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - tcx.arena.alloc_slice(&tcx.cstore.crates_untracked()) - }; - providers.output_filenames = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - tcx.output_filenames.clone() - }; - providers.features_query = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - tcx.arena.alloc(tcx.sess.features_untracked().clone()) - }; - providers.is_panic_runtime = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - attr::contains_name(tcx.hir().krate_attrs(), sym::panic_runtime) - }; - providers.is_compiler_builtins = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins) - }; - providers.has_panic_handler = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - // We want to check if the panic handler was defined in this crate - tcx.lang_items().panic_impl().map_or(false, |did| did.is_local()) - }; -} diff --git a/src/librustc/ty/diagnostics.rs b/src/librustc/ty/diagnostics.rs deleted file mode 100644 index d1eb21e25ff..00000000000 --- a/src/librustc/ty/diagnostics.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Diagnostics related methods for `TyS`. - -use crate::ty::sty::InferTy; -use crate::ty::TyKind::*; -use crate::ty::TyS; - -impl<'tcx> TyS<'tcx> { - /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive. - pub fn is_primitive_ty(&self) -> bool { - match self.kind { - Bool - | Char - | Str - | Int(_) - | Uint(_) - | Float(_) - | Infer(InferTy::IntVar(_)) - | Infer(InferTy::FloatVar(_)) - | Infer(InferTy::FreshIntTy(_)) - | Infer(InferTy::FreshFloatTy(_)) => true, - _ => false, - } - } - - /// Whether the type is succinctly representable as a type instead of just referred to with a - /// description in error messages. This is used in the main error message. - pub fn is_simple_ty(&self) -> bool { - match self.kind { - Bool - | Char - | Str - | Int(_) - | Uint(_) - | Float(_) - | Infer(InferTy::IntVar(_)) - | Infer(InferTy::FloatVar(_)) - | Infer(InferTy::FreshIntTy(_)) - | Infer(InferTy::FreshFloatTy(_)) => true, - Ref(_, x, _) | Array(x, _) | Slice(x) => x.peel_refs().is_simple_ty(), - Tuple(tys) if tys.is_empty() => true, - _ => false, - } - } - - /// Whether the type is succinctly representable as a type instead of just referred to with a - /// description in error messages. This is used in the primary span label. Beyond what - /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to - /// ADTs with no type arguments. - pub fn is_simple_text(&self) -> bool { - match self.kind { - Adt(_, substs) => substs.types().next().is_none(), - Ref(_, ty, _) => ty.is_simple_text(), - _ => self.is_simple_ty(), - } - } - - /// Whether the type can be safely suggested during error recovery. - pub fn is_suggestable(&self) -> bool { - match self.kind { - Opaque(..) | FnDef(..) | FnPtr(..) | Dynamic(..) | Closure(..) | Infer(..) - | Projection(..) => false, - _ => true, - } - } -} diff --git a/src/librustc/ty/erase_regions.rs b/src/librustc/ty/erase_regions.rs deleted file mode 100644 index 4bf08096ede..00000000000 --- a/src/librustc/ty/erase_regions.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::{self, Ty, TyCtxt, TypeFlags}; - -pub(super) fn provide(providers: &mut ty::query::Providers<'_>) { - *providers = ty::query::Providers { erase_regions_ty, ..*providers }; -} - -fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - // N.B., use `super_fold_with` here. If we used `fold_with`, it - // could invoke the `erase_regions_ty` query recursively. - ty.super_fold_with(&mut RegionEraserVisitor { tcx }) -} - -impl<'tcx> TyCtxt<'tcx> { - /// Returns an equivalent value with all free regions removed (note - /// that late-bound regions remain, because they are important for - /// subtyping, but they are anonymized and normalized as well).. - pub fn erase_regions<T>(self, value: &T) -> T - where - T: TypeFoldable<'tcx>, - { - // If there's nothing to erase avoid performing the query at all - if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) { - return value.clone(); - } - - let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self }); - debug!("erase_regions({:?}) = {:?}", value, value1); - value1 - } -} - -struct RegionEraserVisitor<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.has_local_value() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) } - } - - fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> - where - T: TypeFoldable<'tcx>, - { - let u = self.tcx.anonymize_late_bound_regions(t); - u.super_fold_with(self) - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - // because late-bound regions affect subtyping, we can't - // erase the bound/free distinction, but we can replace - // all free regions with 'erased. - // - // Note that we *CAN* replace early-bound regions -- the - // type system never "sees" those, they get substituted - // away. In codegen, they will always be erased to 'erased - // whenever a substitution occurs. - match *r { - ty::ReLateBound(..) => r, - _ => self.tcx.lifetimes.re_erased, - } - } -} diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs deleted file mode 100644 index 6c5458e6e58..00000000000 --- a/src/librustc/ty/error.rs +++ /dev/null @@ -1,495 +0,0 @@ -use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt}; -use rustc_errors::{pluralize, Applicability, DiagnosticBuilder}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_span::Span; -use rustc_target::spec::abi; -use syntax::ast; - -use std::borrow::Cow; -use std::fmt; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)] -pub struct ExpectedFound<T> { - pub expected: T, - pub found: T, -} - -impl<T> ExpectedFound<T> { - pub fn new(a_is_expected: bool, a: T, b: T) -> Self { - if a_is_expected { - ExpectedFound { expected: a, found: b } - } else { - ExpectedFound { expected: b, found: a } - } - } -} - -// Data structures used in type unification -#[derive(Clone, Debug, TypeFoldable)] -pub enum TypeError<'tcx> { - Mismatch, - UnsafetyMismatch(ExpectedFound<hir::Unsafety>), - AbiMismatch(ExpectedFound<abi::Abi>), - Mutability, - TupleSize(ExpectedFound<usize>), - FixedArraySize(ExpectedFound<u64>), - ArgCount, - - RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), - RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>), - RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>), - RegionsPlaceholderMismatch, - - Sorts(ExpectedFound<Ty<'tcx>>), - IntMismatch(ExpectedFound<ty::IntVarValue>), - FloatMismatch(ExpectedFound<ast::FloatTy>), - Traits(ExpectedFound<DefId>), - VariadicMismatch(ExpectedFound<bool>), - - /// Instantiating a type variable with the given type would have - /// created a cycle (because it appears somewhere within that - /// type). - CyclicTy(Ty<'tcx>), - ProjectionMismatched(ExpectedFound<DefId>), - ProjectionBoundsLength(ExpectedFound<usize>), - ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>), - ObjectUnsafeCoercion(DefId), - ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), - - IntrinsicCast, -} - -pub enum UnconstrainedNumeric { - UnconstrainedFloat, - UnconstrainedInt, - Neither, -} - -/// Explains the source of a type err in a short, human readable way. This is meant to be placed -/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` -/// afterwards to present additional details, particularly when it comes to lifetime-related -/// errors. -impl<'tcx> fmt::Display for TypeError<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use self::TypeError::*; - fn report_maybe_different( - f: &mut fmt::Formatter<'_>, - expected: &str, - found: &str, - ) -> fmt::Result { - // A naive approach to making sure that we're not reporting silly errors such as: - // (expected closure, found closure). - if expected == found { - write!(f, "expected {}, found a different {}", expected, found) - } else { - write!(f, "expected {}, found {}", expected, found) - } - } - - let br_string = |br: ty::BoundRegion| match br { - ty::BrNamed(_, name) => format!(" {}", name), - _ => String::new(), - }; - - match *self { - CyclicTy(_) => write!(f, "cyclic type of infinite size"), - Mismatch => write!(f, "types differ"), - UnsafetyMismatch(values) => { - write!(f, "expected {} fn, found {} fn", values.expected, values.found) - } - AbiMismatch(values) => { - write!(f, "expected {} fn, found {} fn", values.expected, values.found) - } - Mutability => write!(f, "types differ in mutability"), - TupleSize(values) => write!( - f, - "expected a tuple with {} element{}, \ - found one with {} element{}", - values.expected, - pluralize!(values.expected), - values.found, - pluralize!(values.found) - ), - FixedArraySize(values) => write!( - f, - "expected an array with a fixed size of {} element{}, \ - found one with {} element{}", - values.expected, - pluralize!(values.expected), - values.found, - pluralize!(values.found) - ), - ArgCount => write!(f, "incorrect number of function parameters"), - RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"), - RegionsInsufficientlyPolymorphic(br, _) => write!( - f, - "expected bound lifetime parameter{}, found concrete lifetime", - br_string(br) - ), - RegionsOverlyPolymorphic(br, _) => write!( - f, - "expected concrete lifetime, found bound lifetime parameter{}", - br_string(br) - ), - RegionsPlaceholderMismatch => write!(f, "one type is more general than the other"), - Sorts(values) => ty::tls::with(|tcx| { - report_maybe_different( - f, - &values.expected.sort_string(tcx), - &values.found.sort_string(tcx), - ) - }), - Traits(values) => ty::tls::with(|tcx| { - report_maybe_different( - f, - &format!("trait `{}`", tcx.def_path_str(values.expected)), - &format!("trait `{}`", tcx.def_path_str(values.found)), - ) - }), - IntMismatch(ref values) => { - write!(f, "expected `{:?}`, found `{:?}`", values.expected, values.found) - } - FloatMismatch(ref values) => { - write!(f, "expected `{:?}`, found `{:?}`", values.expected, values.found) - } - VariadicMismatch(ref values) => write!( - f, - "expected {} fn, found {} function", - if values.expected { "variadic" } else { "non-variadic" }, - if values.found { "variadic" } else { "non-variadic" } - ), - ProjectionMismatched(ref values) => ty::tls::with(|tcx| { - write!( - f, - "expected {}, found {}", - tcx.def_path_str(values.expected), - tcx.def_path_str(values.found) - ) - }), - ProjectionBoundsLength(ref values) => write!( - f, - "expected {} associated type binding{}, found {}", - values.expected, - pluralize!(values.expected), - values.found - ), - ExistentialMismatch(ref values) => report_maybe_different( - f, - &format!("trait `{}`", values.expected), - &format!("trait `{}`", values.found), - ), - ConstMismatch(ref values) => { - write!(f, "expected `{}`, found `{}`", values.expected, values.found) - } - IntrinsicCast => write!(f, "cannot coerce intrinsics to function pointers"), - ObjectUnsafeCoercion(_) => write!(f, "coercion to object-unsafe trait object"), - } - } -} - -impl<'tcx> TypeError<'tcx> { - pub fn must_include_note(&self) -> bool { - use self::TypeError::*; - match self { - CyclicTy(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) - | Sorts(_) | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) => false, - - Mutability - | TupleSize(_) - | ArgCount - | RegionsDoesNotOutlive(..) - | RegionsInsufficientlyPolymorphic(..) - | RegionsOverlyPolymorphic(..) - | RegionsPlaceholderMismatch - | Traits(_) - | ProjectionMismatched(_) - | ProjectionBoundsLength(_) - | ExistentialMismatch(_) - | ConstMismatch(_) - | IntrinsicCast - | ObjectUnsafeCoercion(_) => true, - } - } -} - -impl<'tcx> ty::TyS<'tcx> { - pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> { - match self.kind { - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { - format!("`{}`", self).into() - } - ty::Tuple(ref tys) if tys.is_empty() => format!("`{}`", self).into(), - - ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(), - ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(), - ty::Array(t, n) => { - let n = tcx.lift(&n).unwrap(); - match n.try_eval_usize(tcx, ty::ParamEnv::empty()) { - _ if t.is_simple_ty() => format!("array `{}`", self).into(), - Some(n) => format!("array of {} element{} ", n, pluralize!(n)).into(), - None => "array".into(), - } - } - ty::Slice(ty) if ty.is_simple_ty() => format!("slice `{}`", self).into(), - ty::Slice(_) => "slice".into(), - ty::RawPtr(_) => "*-ptr".into(), - ty::Ref(_, ty, mutbl) => { - let tymut = ty::TypeAndMut { ty, mutbl }; - let tymut_string = tymut.to_string(); - if tymut_string != "_" - && (ty.is_simple_text() || tymut_string.len() < "mutable reference".len()) - { - format!("`&{}`", tymut_string).into() - } else { - // Unknown type name, it's long or has type arguments - match mutbl { - hir::Mutability::Mut => "mutable reference", - _ => "reference", - } - .into() - } - } - ty::FnDef(..) => "fn item".into(), - ty::FnPtr(_) => "fn pointer".into(), - ty::Dynamic(ref inner, ..) => { - if let Some(principal) = inner.principal() { - format!("trait object `dyn {}`", tcx.def_path_str(principal.def_id())).into() - } else { - "trait object".into() - } - } - ty::Closure(..) => "closure".into(), - ty::Generator(..) => "generator".into(), - ty::GeneratorWitness(..) => "generator witness".into(), - ty::Tuple(..) => "tuple".into(), - ty::Infer(ty::TyVar(_)) => "inferred type".into(), - ty::Infer(ty::IntVar(_)) => "integer".into(), - ty::Infer(ty::FloatVar(_)) => "floating-point number".into(), - ty::Placeholder(..) => "placeholder type".into(), - ty::Bound(..) => "bound type".into(), - ty::Infer(ty::FreshTy(_)) => "fresh type".into(), - ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(), - ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(), - ty::Projection(_) => "associated type".into(), - ty::UnnormalizedProjection(_) => "non-normalized associated type".into(), - ty::Param(p) => format!("type parameter `{}`", p).into(), - ty::Opaque(..) => "opaque type".into(), - ty::Error => "type error".into(), - } - } - - pub fn prefix_string(&self) -> Cow<'static, str> { - match self.kind { - ty::Infer(_) - | ty::Error - | ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Never => "type".into(), - ty::Tuple(ref tys) if tys.is_empty() => "unit type".into(), - ty::Adt(def, _) => def.descr().into(), - ty::Foreign(_) => "extern type".into(), - ty::Array(..) => "array".into(), - ty::Slice(_) => "slice".into(), - ty::RawPtr(_) => "raw pointer".into(), - ty::Ref(.., mutbl) => match mutbl { - hir::Mutability::Mut => "mutable reference", - _ => "reference", - } - .into(), - ty::FnDef(..) => "fn item".into(), - ty::FnPtr(_) => "fn pointer".into(), - ty::Dynamic(..) => "trait object".into(), - ty::Closure(..) => "closure".into(), - ty::Generator(..) => "generator".into(), - ty::GeneratorWitness(..) => "generator witness".into(), - ty::Tuple(..) => "tuple".into(), - ty::Placeholder(..) => "higher-ranked type".into(), - ty::Bound(..) => "bound type variable".into(), - ty::Projection(_) => "associated type".into(), - ty::UnnormalizedProjection(_) => "associated type".into(), - ty::Param(_) => "type parameter".into(), - ty::Opaque(..) => "opaque type".into(), - } - } -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn note_and_explain_type_err( - self, - db: &mut DiagnosticBuilder<'_>, - err: &TypeError<'tcx>, - sp: Span, - body_owner_def_id: DefId, - ) { - use self::TypeError::*; - - match err { - Sorts(values) => { - let expected_str = values.expected.sort_string(self); - let found_str = values.found.sort_string(self); - if expected_str == found_str && expected_str == "closure" { - db.note("no two closures, even if identical, have the same type"); - db.help("consider boxing your closure and/or using it as a trait object"); - } - if expected_str == found_str && expected_str == "opaque type" { - // Issue #63167 - db.note("distinct uses of `impl Trait` result in different opaque types"); - let e_str = values.expected.to_string(); - let f_str = values.found.to_string(); - if &e_str == &f_str && &e_str == "impl std::future::Future" { - // FIXME: use non-string based check. - db.help( - "if both `Future`s have the same `Output` type, consider \ - `.await`ing on both of them", - ); - } - } - match (&values.expected.kind, &values.found.kind) { - (ty::Float(_), ty::Infer(ty::IntVar(_))) => { - if let Ok( - // Issue #53280 - snippet, - ) = self.sess.source_map().span_to_snippet(sp) - { - if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') { - db.span_suggestion( - sp, - "use a float literal", - format!("{}.0", snippet), - Applicability::MachineApplicable, - ); - } - } - } - (ty::Param(expected), ty::Param(found)) => { - let generics = self.generics_of(body_owner_def_id); - let e_span = self.def_span(generics.type_param(expected, self).def_id); - if !sp.contains(e_span) { - db.span_label(e_span, "expected type parameter"); - } - let f_span = self.def_span(generics.type_param(found, self).def_id); - if !sp.contains(f_span) { - db.span_label(f_span, "found type parameter"); - } - db.note( - "a type parameter was expected, but a different one was found; \ - you might be missing a type parameter or trait bound", - ); - db.note( - "for more information, visit \ - https://doc.rust-lang.org/book/ch10-02-traits.html\ - #traits-as-parameters", - ); - } - (ty::Projection(_), ty::Projection(_)) => { - db.note("an associated type was expected, but a different one was found"); - } - (ty::Param(_), ty::Projection(_)) | (ty::Projection(_), ty::Param(_)) => { - db.note("you might be missing a type parameter or trait bound"); - } - (ty::Param(p), _) | (_, ty::Param(p)) => { - let generics = self.generics_of(body_owner_def_id); - let p_span = self.def_span(generics.type_param(p, self).def_id); - if !sp.contains(p_span) { - db.span_label(p_span, "this type parameter"); - } - db.help("type parameters must be constrained to match other types"); - if self.sess.teach(&db.get_code().unwrap()) { - db.help( - "given a type parameter `T` and a method `foo`: -``` -trait Trait<T> { fn foo(&self) -> T; } -``` -the only ways to implement method `foo` are: -- constrain `T` with an explicit type: -``` -impl Trait<String> for X { - fn foo(&self) -> String { String::new() } -} -``` -- add a trait bound to `T` and call a method on that trait that returns `Self`: -``` -impl<T: std::default::Default> Trait<T> for X { - fn foo(&self) -> T { <T as std::default::Default>::default() } -} -``` -- change `foo` to return an argument of type `T`: -``` -impl<T> Trait<T> for X { - fn foo(&self, x: T) -> T { x } -} -```", - ); - } - db.note( - "for more information, visit \ - https://doc.rust-lang.org/book/ch10-02-traits.html\ - #traits-as-parameters", - ); - } - (ty::Projection(_), _) => { - db.note(&format!( - "consider constraining the associated type `{}` to `{}` or calling a \ - method that returns `{}`", - values.expected, values.found, values.expected, - )); - if self.sess.teach(&db.get_code().unwrap()) { - db.help( - "given an associated type `T` and a method `foo`: -``` -trait Trait { - type T; - fn foo(&self) -> Self::T; -} -``` -the only way of implementing method `foo` is to constrain `T` with an explicit associated type: -``` -impl Trait for X { - type T = String; - fn foo(&self) -> Self::T { String::new() } -} -```", - ); - } - db.note( - "for more information, visit \ - https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", - ); - } - (_, ty::Projection(_)) => { - db.note(&format!( - "consider constraining the associated type `{}` to `{}`", - values.found, values.expected, - )); - db.note( - "for more information, visit \ - https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", - ); - } - _ => {} - } - debug!( - "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})", - values.expected, values.expected.kind, values.found, values.found.kind, - ); - } - CyclicTy(ty) => { - // Watch out for various cases of cyclic types and try to explain. - if ty.is_closure() || ty.is_generator() { - db.note( - "closures cannot capture themselves or take themselves as argument;\n\ - this error may be the result of a recent compiler bug-fix,\n\ - see issue #46062 <https://github.com/rust-lang/rust/issues/46062>\n\ - for more information", - ); - } - } - _ => {} - } - } -} diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs deleted file mode 100644 index 5aa8bd9df2a..00000000000 --- a/src/librustc/ty/fast_reject.rs +++ /dev/null @@ -1,174 +0,0 @@ -use crate::ich::StableHashingContext; -use crate::ty::{self, Ty, TyCtxt}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::def_id::DefId; -use std::fmt::Debug; -use std::hash::Hash; -use std::mem; -use syntax::ast; - -use self::SimplifiedTypeGen::*; - -pub type SimplifiedType = SimplifiedTypeGen<DefId>; - -/// See `simplify_type` -/// -/// Note that we keep this type generic over the type of identifier it uses -/// because we sometimes need to use SimplifiedTypeGen values as stable sorting -/// keys (in which case we use a DefPathHash as id-type) but in the general case -/// the non-stable but fast to construct DefId-version is the better choice. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, RustcEncodable, RustcDecodable)] -pub enum SimplifiedTypeGen<D> -where - D: Copy + Debug + Ord + Eq, -{ - BoolSimplifiedType, - CharSimplifiedType, - IntSimplifiedType(ast::IntTy), - UintSimplifiedType(ast::UintTy), - FloatSimplifiedType(ast::FloatTy), - AdtSimplifiedType(D), - StrSimplifiedType, - ArraySimplifiedType, - PtrSimplifiedType, - NeverSimplifiedType, - TupleSimplifiedType(usize), - /// A trait object, all of whose components are markers - /// (e.g., `dyn Send + Sync`). - MarkerTraitObjectSimplifiedType, - TraitSimplifiedType(D), - ClosureSimplifiedType(D), - GeneratorSimplifiedType(D), - GeneratorWitnessSimplifiedType(usize), - OpaqueSimplifiedType(D), - FunctionSimplifiedType(usize), - ParameterSimplifiedType, - ForeignSimplifiedType(DefId), -} - -/// Tries to simplify a type by dropping type parameters, deref'ing away any reference types, etc. -/// The idea is to get something simple that we can use to quickly decide if two types could unify -/// during method lookup. -/// -/// If `can_simplify_params` is false, then we will fail to simplify type parameters entirely. This -/// is useful when those type parameters would be instantiated with fresh type variables, since -/// then we can't say much about whether two types would unify. Put another way, -/// `can_simplify_params` should be true if type parameters appear free in `ty` and `false` if they -/// are to be considered bound. -pub fn simplify_type( - tcx: TyCtxt<'_>, - ty: Ty<'_>, - can_simplify_params: bool, -) -> Option<SimplifiedType> { - match ty.kind { - ty::Bool => Some(BoolSimplifiedType), - ty::Char => Some(CharSimplifiedType), - ty::Int(int_type) => Some(IntSimplifiedType(int_type)), - ty::Uint(uint_type) => Some(UintSimplifiedType(uint_type)), - ty::Float(float_type) => Some(FloatSimplifiedType(float_type)), - ty::Adt(def, _) => Some(AdtSimplifiedType(def.did)), - ty::Str => Some(StrSimplifiedType), - ty::Array(..) | ty::Slice(_) => Some(ArraySimplifiedType), - ty::RawPtr(_) => Some(PtrSimplifiedType), - ty::Dynamic(ref trait_info, ..) => match trait_info.principal_def_id() { - Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => { - Some(TraitSimplifiedType(principal_def_id)) - } - _ => Some(MarkerTraitObjectSimplifiedType), - }, - ty::Ref(_, ty, _) => { - // since we introduce auto-refs during method lookup, we - // just treat &T and T as equivalent from the point of - // view of possibly unifying - simplify_type(tcx, ty, can_simplify_params) - } - ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)), - ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)), - ty::GeneratorWitness(ref tys) => { - Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len())) - } - ty::Never => Some(NeverSimplifiedType), - ty::Tuple(ref tys) => Some(TupleSimplifiedType(tys.len())), - ty::FnPtr(ref f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())), - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - ty::Projection(_) | ty::Param(_) => { - if can_simplify_params { - // In normalized types, projections don't unify with - // anything. when lazy normalization happens, this - // will change. It would still be nice to have a way - // to deal with known-not-to-unify-with-anything - // projections (e.g., the likes of <__S as Encoder>::Error). - Some(ParameterSimplifiedType) - } else { - None - } - } - ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)), - ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)), - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error => None, - } -} - -impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> { - pub fn map_def<U, F>(self, map: F) -> SimplifiedTypeGen<U> - where - F: Fn(D) -> U, - U: Copy + Debug + Ord + Eq, - { - match self { - BoolSimplifiedType => BoolSimplifiedType, - CharSimplifiedType => CharSimplifiedType, - IntSimplifiedType(t) => IntSimplifiedType(t), - UintSimplifiedType(t) => UintSimplifiedType(t), - FloatSimplifiedType(t) => FloatSimplifiedType(t), - AdtSimplifiedType(d) => AdtSimplifiedType(map(d)), - StrSimplifiedType => StrSimplifiedType, - ArraySimplifiedType => ArraySimplifiedType, - PtrSimplifiedType => PtrSimplifiedType, - NeverSimplifiedType => NeverSimplifiedType, - MarkerTraitObjectSimplifiedType => MarkerTraitObjectSimplifiedType, - TupleSimplifiedType(n) => TupleSimplifiedType(n), - TraitSimplifiedType(d) => TraitSimplifiedType(map(d)), - ClosureSimplifiedType(d) => ClosureSimplifiedType(map(d)), - GeneratorSimplifiedType(d) => GeneratorSimplifiedType(map(d)), - GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n), - OpaqueSimplifiedType(d) => OpaqueSimplifiedType(map(d)), - FunctionSimplifiedType(n) => FunctionSimplifiedType(n), - ParameterSimplifiedType => ParameterSimplifiedType, - ForeignSimplifiedType(d) => ForeignSimplifiedType(d), - } - } -} - -impl<'a, D> HashStable<StableHashingContext<'a>> for SimplifiedTypeGen<D> -where - D: Copy + Debug + Ord + Eq + HashStable<StableHashingContext<'a>>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - BoolSimplifiedType - | CharSimplifiedType - | StrSimplifiedType - | ArraySimplifiedType - | PtrSimplifiedType - | NeverSimplifiedType - | ParameterSimplifiedType - | MarkerTraitObjectSimplifiedType => { - // nothing to do - } - IntSimplifiedType(t) => t.hash_stable(hcx, hasher), - UintSimplifiedType(t) => t.hash_stable(hcx, hasher), - FloatSimplifiedType(t) => t.hash_stable(hcx, hasher), - AdtSimplifiedType(d) => d.hash_stable(hcx, hasher), - TupleSimplifiedType(n) => n.hash_stable(hcx, hasher), - TraitSimplifiedType(d) => d.hash_stable(hcx, hasher), - ClosureSimplifiedType(d) => d.hash_stable(hcx, hasher), - GeneratorSimplifiedType(d) => d.hash_stable(hcx, hasher), - GeneratorWitnessSimplifiedType(n) => n.hash_stable(hcx, hasher), - OpaqueSimplifiedType(d) => d.hash_stable(hcx, hasher), - FunctionSimplifiedType(n) => n.hash_stable(hcx, hasher), - ForeignSimplifiedType(d) => d.hash_stable(hcx, hasher), - } - } -} diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs deleted file mode 100644 index 4546eadc6e6..00000000000 --- a/src/librustc/ty/flags.rs +++ /dev/null @@ -1,264 +0,0 @@ -use crate::ty::subst::{GenericArgKind, SubstsRef}; -use crate::ty::{self, InferConst, Ty, TypeFlags}; - -#[derive(Debug)] -pub struct FlagComputation { - pub flags: TypeFlags, - - // see `TyS::outer_exclusive_binder` for details - pub outer_exclusive_binder: ty::DebruijnIndex, -} - -impl FlagComputation { - fn new() -> FlagComputation { - FlagComputation { flags: TypeFlags::empty(), outer_exclusive_binder: ty::INNERMOST } - } - - #[allow(rustc::usage_of_ty_tykind)] - pub fn for_kind(kind: &ty::TyKind<'_>) -> FlagComputation { - let mut result = FlagComputation::new(); - result.add_kind(kind); - result - } - - pub fn for_const(c: &ty::Const<'_>) -> TypeFlags { - let mut result = FlagComputation::new(); - result.add_const(c); - result.flags - } - - fn add_flags(&mut self, flags: TypeFlags) { - self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS); - } - - /// indicates that `self` refers to something at binding level `binder` - fn add_binder(&mut self, binder: ty::DebruijnIndex) { - let exclusive_binder = binder.shifted_in(1); - self.add_exclusive_binder(exclusive_binder); - } - - /// indicates that `self` refers to something *inside* binding - /// level `binder` -- not bound by `binder`, but bound by the next - /// binder internal to it - fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) { - self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder); - } - - /// Adds the flags/depth from a set of types that appear within the current type, but within a - /// region binder. - fn add_bound_computation(&mut self, computation: &FlagComputation) { - self.add_flags(computation.flags); - - // The types that contributed to `computation` occurred within - // a region binder, so subtract one from the region depth - // within when adding the depth to `self`. - let outer_exclusive_binder = computation.outer_exclusive_binder; - if outer_exclusive_binder > ty::INNERMOST { - self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1)); - } // otherwise, this binder captures nothing - } - - #[allow(rustc::usage_of_ty_tykind)] - fn add_kind(&mut self, kind: &ty::TyKind<'_>) { - match kind { - &ty::Bool - | &ty::Char - | &ty::Int(_) - | &ty::Float(_) - | &ty::Uint(_) - | &ty::Never - | &ty::Str - | &ty::Foreign(..) => {} - - // You might think that we could just return Error for - // any type containing Error as a component, and get - // rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with - // the exception of function types that return bot). - // But doing so caused sporadic memory corruption, and - // neither I (tjc) nor nmatsakis could figure out why, - // so we're doing it this way. - &ty::Error => self.add_flags(TypeFlags::HAS_TY_ERR), - - &ty::Param(_) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); - self.add_flags(TypeFlags::HAS_PARAMS); - } - - &ty::Generator(_, ref substs, _) => { - self.add_flags(TypeFlags::HAS_TY_CLOSURE); - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); - self.add_substs(substs); - } - - &ty::GeneratorWitness(ref ts) => { - let mut computation = FlagComputation::new(); - computation.add_tys(&ts.skip_binder()[..]); - self.add_bound_computation(&computation); - } - - &ty::Closure(_, ref substs) => { - self.add_flags(TypeFlags::HAS_TY_CLOSURE); - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); - self.add_substs(substs); - } - - &ty::Bound(debruijn, _) => { - self.add_binder(debruijn); - } - - &ty::Placeholder(..) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); - self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER); - } - - &ty::Infer(infer) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right? - self.add_flags(TypeFlags::HAS_TY_INFER); - match infer { - ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {} - - ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => { - self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX) - } - } - } - - &ty::Adt(_, substs) => { - self.add_substs(substs); - } - - &ty::Projection(ref data) => { - self.add_flags(TypeFlags::HAS_PROJECTION); - self.add_projection_ty(data); - } - - &ty::UnnormalizedProjection(ref data) => { - self.add_flags(TypeFlags::HAS_PROJECTION); - self.add_projection_ty(data); - } - - &ty::Opaque(_, substs) => { - self.add_flags(TypeFlags::HAS_PROJECTION | TypeFlags::HAS_TY_OPAQUE); - self.add_substs(substs); - } - - &ty::Dynamic(ref obj, r) => { - let mut computation = FlagComputation::new(); - for predicate in obj.skip_binder().iter() { - match *predicate { - ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs), - ty::ExistentialPredicate::Projection(p) => { - let mut proj_computation = FlagComputation::new(); - proj_computation.add_existential_projection(&p); - self.add_bound_computation(&proj_computation); - } - ty::ExistentialPredicate::AutoTrait(_) => {} - } - } - self.add_bound_computation(&computation); - self.add_region(r); - } - - &ty::Array(tt, len) => { - self.add_ty(tt); - self.add_const(len); - } - - &ty::Slice(tt) => self.add_ty(tt), - - &ty::RawPtr(ref m) => { - self.add_ty(m.ty); - } - - &ty::Ref(r, ty, _) => { - self.add_region(r); - self.add_ty(ty); - } - - &ty::Tuple(ref substs) => { - self.add_substs(substs); - } - - &ty::FnDef(_, substs) => { - self.add_substs(substs); - } - - &ty::FnPtr(f) => { - self.add_fn_sig(f); - } - } - } - - fn add_ty(&mut self, ty: Ty<'_>) { - self.add_flags(ty.flags); - self.add_exclusive_binder(ty.outer_exclusive_binder); - } - - fn add_tys(&mut self, tys: &[Ty<'_>]) { - for &ty in tys { - self.add_ty(ty); - } - } - - fn add_fn_sig(&mut self, fn_sig: ty::PolyFnSig<'_>) { - let mut computation = FlagComputation::new(); - - computation.add_tys(fn_sig.skip_binder().inputs()); - computation.add_ty(fn_sig.skip_binder().output()); - - self.add_bound_computation(&computation); - } - - fn add_region(&mut self, r: ty::Region<'_>) { - self.add_flags(r.type_flags()); - if let ty::ReLateBound(debruijn, _) = *r { - self.add_binder(debruijn); - } - } - - fn add_const(&mut self, c: &ty::Const<'_>) { - self.add_ty(c.ty); - match c.val { - ty::ConstKind::Unevaluated(_, substs, _) => { - self.add_substs(substs); - self.add_flags(TypeFlags::HAS_PROJECTION); - } - ty::ConstKind::Infer(infer) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES | TypeFlags::HAS_CT_INFER); - match infer { - InferConst::Fresh(_) => {} - InferConst::Var(_) => self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX), - } - } - ty::ConstKind::Bound(debruijn, _) => self.add_binder(debruijn), - ty::ConstKind::Param(_) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); - self.add_flags(TypeFlags::HAS_PARAMS); - } - ty::ConstKind::Placeholder(_) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); - self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); - } - ty::ConstKind::Value(_) => {} - } - } - - fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) { - self.add_substs(projection.substs); - self.add_ty(projection.ty); - } - - fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy<'_>) { - self.add_substs(projection_ty.substs); - } - - fn add_substs(&mut self, substs: SubstsRef<'_>) { - for kind in substs { - match kind.unpack() { - GenericArgKind::Type(ty) => self.add_ty(ty), - GenericArgKind::Lifetime(lt) => self.add_region(lt), - GenericArgKind::Const(ct) => self.add_const(ct), - } - } - } -} diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs deleted file mode 100644 index 3212bc72417..00000000000 --- a/src/librustc/ty/fold.rs +++ /dev/null @@ -1,1002 +0,0 @@ -//! Generalized type folding mechanism. The setup is a bit convoluted -//! but allows for convenient usage. Let T be an instance of some -//! "foldable type" (one which implements `TypeFoldable`) and F be an -//! instance of a "folder" (a type which implements `TypeFolder`). Then -//! the setup is intended to be: -//! -//! T.fold_with(F) --calls--> F.fold_T(T) --calls--> T.super_fold_with(F) -//! -//! This way, when you define a new folder F, you can override -//! `fold_T()` to customize the behavior, and invoke `T.super_fold_with()` -//! to get the original behavior. Meanwhile, to actually fold -//! something, you can just write `T.fold_with(F)`, which is -//! convenient. (Note that `fold_with` will also transparently handle -//! things like a `Vec<T>` where T is foldable and so on.) -//! -//! In this ideal setup, the only function that actually *does* -//! anything is `T.super_fold_with()`, which traverses the type `T`. -//! Moreover, `T.super_fold_with()` should only ever call `T.fold_with()`. -//! -//! In some cases, we follow a degenerate pattern where we do not have -//! a `fold_T` method. Instead, `T.fold_with` traverses the structure directly. -//! This is suboptimal because the behavior cannot be overridden, but it's -//! much less work to implement. If you ever *do* need an override that -//! doesn't exist, it's not hard to convert the degenerate pattern into the -//! proper thing. -//! -//! A `TypeFoldable` T can also be visited by a `TypeVisitor` V using similar setup: -//! -//! T.visit_with(V) --calls--> V.visit_T(T) --calls--> T.super_visit_with(V). -//! -//! These methods return true to indicate that the visitor has found what it is -//! looking for, and does not need to visit anything else. - -use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; - -use rustc_data_structures::fx::FxHashSet; -use std::collections::BTreeMap; -use std::fmt; - -/// This trait is implemented for every type that can be folded. -/// Basically, every type that has a corresponding method in `TypeFolder`. -/// -/// To implement this conveniently, use the derive macro located in librustc_macros. -pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self; - fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - self.super_fold_with(folder) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool; - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.super_visit_with(visitor) - } - - /// Returns `true` if `self` has any late-bound regions that are either - /// bound by `binder` or bound by some binder outside of `binder`. - /// If `binder` is `ty::INNERMOST`, this indicates whether - /// there are any late-bound regions that appear free. - fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { - self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }) - } - - /// Returns `true` if this `self` has any regions that escape `binder` (and - /// hence are not bound by it). - fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool { - self.has_vars_bound_at_or_above(binder.shifted_in(1)) - } - - fn has_escaping_bound_vars(&self) -> bool { - self.has_vars_bound_at_or_above(ty::INNERMOST) - } - - fn has_type_flags(&self, flags: TypeFlags) -> bool { - self.visit_with(&mut HasTypeFlagsVisitor { flags }) - } - fn has_projections(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PROJECTION) - } - fn has_opaque_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) - } - fn references_error(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_ERR) - } - fn has_param_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PARAMS) - } - fn has_infer_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INFER) - } - fn has_infer_consts(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_CT_INFER) - } - fn has_local_value(&self) -> bool { - self.has_type_flags(TypeFlags::KEEP_IN_LOCAL_TCX) - } - fn needs_infer(&self) -> bool { - self.has_type_flags( - TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER | TypeFlags::HAS_CT_INFER, - ) - } - fn has_placeholders(&self) -> bool { - self.has_type_flags( - TypeFlags::HAS_RE_PLACEHOLDER - | TypeFlags::HAS_TY_PLACEHOLDER - | TypeFlags::HAS_CT_PLACEHOLDER, - ) - } - fn needs_subst(&self) -> bool { - self.has_type_flags(TypeFlags::NEEDS_SUBST) - } - fn has_re_placeholders(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER) - } - fn has_closure_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_CLOSURE) - } - /// "Free" regions in this context means that it has any region - /// that is not (a) erased or (b) late-bound. - fn has_free_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) - } - - fn has_erased_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_ERASED) - } - - /// True if there are any un-erased free regions. - fn has_erasable_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) - } - - /// Indicates whether this value references only 'global' - /// generic parameters that are the same regardless of what fn we are - /// in. This is used for caching. - fn is_global(&self) -> bool { - !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES) - } - - /// True if there are any late-bound regions - fn has_late_bound_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND) - } - - /// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`. - fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> bool) -> bool { - pub struct Visitor<F>(F); - - impl<'tcx, F: FnMut(Ty<'tcx>) -> bool> TypeVisitor<'tcx> for Visitor<F> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - self.0(ty) - } - } - - self.visit_with(&mut Visitor(visit)) - } -} - -impl TypeFoldable<'tcx> for hir::Constness { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { - *self - } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { - false - } -} - -/// The `TypeFolder` trait defines the actual *folding*. There is a -/// method defined for every foldable type. Each of these has a -/// default implementation that does an "identity" fold. Within each -/// identity fold, it should invoke `foo.fold_with(self)` to fold each -/// sub-item. -pub trait TypeFolder<'tcx>: Sized { - fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; - - fn fold_binder<T>(&mut self, t: &Binder<T>) -> Binder<T> - where - T: TypeFoldable<'tcx>, - { - t.super_fold_with(self) - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - t.super_fold_with(self) - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - r.super_fold_with(self) - } - - fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - c.super_fold_with(self) - } -} - -pub trait TypeVisitor<'tcx>: Sized { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { - t.super_visit_with(self) - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - r.super_visit_with(self) - } - - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { - c.super_visit_with(self) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Some sample folders - -pub struct BottomUpFolder<'tcx, F, G, H> -where - F: FnMut(Ty<'tcx>) -> Ty<'tcx>, - G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, - H: FnMut(&'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>, -{ - pub tcx: TyCtxt<'tcx>, - pub ty_op: F, - pub lt_op: G, - pub ct_op: H, -} - -impl<'tcx, F, G, H> TypeFolder<'tcx> for BottomUpFolder<'tcx, F, G, H> -where - F: FnMut(Ty<'tcx>) -> Ty<'tcx>, - G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, - H: FnMut(&'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>, -{ - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - let t = ty.super_fold_with(self); - (self.ty_op)(t) - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - let r = r.super_fold_with(self); - (self.lt_op)(r) - } - - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - let ct = ct.super_fold_with(self); - (self.ct_op)(ct) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Region folder - -impl<'tcx> TyCtxt<'tcx> { - /// Collects the free and escaping regions in `value` into `region_set`. Returns - /// whether any late-bound regions were skipped - pub fn collect_regions<T>(self, value: &T, region_set: &mut FxHashSet<ty::Region<'tcx>>) -> bool - where - T: TypeFoldable<'tcx>, - { - let mut have_bound_regions = false; - self.fold_regions(value, &mut have_bound_regions, |r, d| { - region_set.insert(self.mk_region(r.shifted_out_to_binder(d))); - r - }); - have_bound_regions - } - - /// Folds the escaping and free regions in `value` using `f`, and - /// sets `skipped_regions` to true if any late-bound region was found - /// and skipped. - pub fn fold_regions<T>( - self, - value: &T, - skipped_regions: &mut bool, - mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, - ) -> T - where - T: TypeFoldable<'tcx>, - { - value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)) - } - - /// Invoke `callback` on every region appearing free in `value`. - pub fn for_each_free_region( - self, - value: &impl TypeFoldable<'tcx>, - mut callback: impl FnMut(ty::Region<'tcx>), - ) { - self.any_free_region_meets(value, |r| { - callback(r); - false - }); - } - - /// Returns `true` if `callback` returns true for every region appearing free in `value`. - pub fn all_free_regions_meet( - self, - value: &impl TypeFoldable<'tcx>, - mut callback: impl FnMut(ty::Region<'tcx>) -> bool, - ) -> bool { - !self.any_free_region_meets(value, |r| !callback(r)) - } - - /// Returns `true` if `callback` returns true for some region appearing free in `value`. - pub fn any_free_region_meets( - self, - value: &impl TypeFoldable<'tcx>, - callback: impl FnMut(ty::Region<'tcx>) -> bool, - ) -> bool { - return value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }); - - struct RegionVisitor<F> { - /// The index of a binder *just outside* the things we have - /// traversed. If we encounter a bound region bound by this - /// binder or one outer to it, it appears free. Example: - /// - /// ``` - /// for<'a> fn(for<'b> fn(), T) - /// ^ ^ ^ ^ - /// | | | | here, would be shifted in 1 - /// | | | here, would be shifted in 2 - /// | | here, would be `INNERMOST` shifted in by 1 - /// | here, initially, binder would be `INNERMOST` - /// ``` - /// - /// You see that, initially, *any* bound value is free, - /// because we've not traversed any binders. As we pass - /// through a binder, we shift the `outer_index` by 1 to - /// account for the new binder that encloses us. - outer_index: ty::DebruijnIndex, - callback: F, - } - - impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F> - where - F: FnMut(ty::Region<'tcx>) -> bool, - { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { - self.outer_index.shift_in(1); - let result = t.skip_binder().visit_with(self); - self.outer_index.shift_out(1); - result - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - match *r { - ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => { - false // ignore bound regions, keep visiting - } - _ => (self.callback)(r), - } - } - - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - // We're only interested in types involving regions - if ty.flags.intersects(TypeFlags::HAS_FREE_REGIONS) { - ty.super_visit_with(self) - } else { - false // keep visiting - } - } - } - } -} - -/// Folds over the substructure of a type, visiting its component -/// types and all regions that occur *free* within it. -/// -/// That is, `Ty` can contain function or method types that bind -/// regions at the call site (`ReLateBound`), and occurrences of -/// regions (aka "lifetimes") that are bound within a type are not -/// visited by this folder; only regions that occur free will be -/// visited by `fld_r`. - -pub struct RegionFolder<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - skipped_regions: &'a mut bool, - - /// Stores the index of a binder *just outside* the stuff we have - /// visited. So this begins as INNERMOST; when we pass through a - /// binder, it is incremented (via `shift_in`). - current_index: ty::DebruijnIndex, - - /// Callback invokes for each free region. The `DebruijnIndex` - /// points to the binder *just outside* the ones we have passed - /// through. - fold_region_fn: - &'a mut (dyn FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx> + 'a), -} - -impl<'a, 'tcx> RegionFolder<'a, 'tcx> { - #[inline] - pub fn new( - tcx: TyCtxt<'tcx>, - skipped_regions: &'a mut bool, - fold_region_fn: &'a mut dyn FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, - ) -> RegionFolder<'a, 'tcx> { - RegionFolder { tcx, skipped_regions, current_index: ty::INNERMOST, fold_region_fn } - } -} - -impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> { - self.current_index.shift_in(1); - let t = t.super_fold_with(self); - self.current_index.shift_out(1); - t - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - ty::ReLateBound(debruijn, _) if debruijn < self.current_index => { - debug!( - "RegionFolder.fold_region({:?}) skipped bound region (current index={:?})", - r, self.current_index - ); - *self.skipped_regions = true; - r - } - _ => { - debug!( - "RegionFolder.fold_region({:?}) folding free region (current_index={:?})", - r, self.current_index - ); - (self.fold_region_fn)(r, self.current_index) - } - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Bound vars replacer - -/// Replaces the escaping bound vars (late bound regions or bound types) in a type. -struct BoundVarReplacer<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - - /// As with `RegionFolder`, represents the index of a binder *just outside* - /// the ones we have visited. - current_index: ty::DebruijnIndex, - - fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), - fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a), - fld_c: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx> + 'a), -} - -impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> { - fn new<F, G, H>(tcx: TyCtxt<'tcx>, fld_r: &'a mut F, fld_t: &'a mut G, fld_c: &'a mut H) -> Self - where - F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, - G: FnMut(ty::BoundTy) -> Ty<'tcx>, - H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, - { - BoundVarReplacer { tcx, current_index: ty::INNERMOST, fld_r, fld_t, fld_c } - } -} - -impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> { - self.current_index.shift_in(1); - let t = t.super_fold_with(self); - self.current_index.shift_out(1); - t - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { - ty::Bound(debruijn, bound_ty) => { - if debruijn == self.current_index { - let fld_t = &mut self.fld_t; - let ty = fld_t(bound_ty); - ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32()) - } else { - t - } - } - _ => { - if !t.has_vars_bound_at_or_above(self.current_index) { - // Nothing more to substitute. - t - } else { - t.super_fold_with(self) - } - } - } - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - ty::ReLateBound(debruijn, br) if debruijn == self.current_index => { - let fld_r = &mut self.fld_r; - let region = fld_r(br); - if let ty::ReLateBound(debruijn1, br) = *region { - // If the callback returns a late-bound region, - // that region should always use the INNERMOST - // debruijn index. Then we adjust it to the - // correct depth. - assert_eq!(debruijn1, ty::INNERMOST); - self.tcx.mk_region(ty::ReLateBound(debruijn, br)) - } else { - region - } - } - _ => r, - } - } - - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty } = *ct { - if debruijn == self.current_index { - let fld_c = &mut self.fld_c; - let ct = fld_c(bound_const, ty); - ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32()) - } else { - ct - } - } else { - if !ct.has_vars_bound_at_or_above(self.current_index) { - // Nothing more to substitute. - ct - } else { - ct.super_fold_with(self) - } - } - } -} - -impl<'tcx> TyCtxt<'tcx> { - /// Replaces all regions bound by the given `Binder` with the - /// results returned by the closure; the closure is expected to - /// return a free region (relative to this binder), and hence the - /// binder is removed in the return type. The closure is invoked - /// once for each unique `BoundRegion`; multiple references to the - /// same `BoundRegion` will reuse the previous result. A map is - /// returned at the end with each bound region and the free region - /// that replaced it. - /// - /// This method only replaces late bound regions and the result may still - /// contain escaping bound types. - pub fn replace_late_bound_regions<T, F>( - self, - value: &Binder<T>, - fld_r: F, - ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) - where - F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, - T: TypeFoldable<'tcx>, - { - // identity for bound types and consts - let fld_t = |bound_ty| self.mk_ty(ty::Bound(ty::INNERMOST, bound_ty)); - let fld_c = |bound_ct, ty| { - self.mk_const(ty::Const { val: ty::ConstKind::Bound(ty::INNERMOST, bound_ct), ty }) - }; - self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) - } - - /// Replaces all escaping bound vars. The `fld_r` closure replaces escaping - /// bound regions; the `fld_t` closure replaces escaping bound types and the `fld_c` - /// closure replaces escaping bound consts. - pub fn replace_escaping_bound_vars<T, F, G, H>( - self, - value: &T, - mut fld_r: F, - mut fld_t: G, - mut fld_c: H, - ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) - where - F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, - G: FnMut(ty::BoundTy) -> Ty<'tcx>, - H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, - T: TypeFoldable<'tcx>, - { - use rustc_data_structures::fx::FxHashMap; - - let mut region_map = BTreeMap::new(); - let mut type_map = FxHashMap::default(); - let mut const_map = FxHashMap::default(); - - if !value.has_escaping_bound_vars() { - (value.clone(), region_map) - } else { - let mut real_fld_r = |br| *region_map.entry(br).or_insert_with(|| fld_r(br)); - - let mut real_fld_t = - |bound_ty| *type_map.entry(bound_ty).or_insert_with(|| fld_t(bound_ty)); - - let mut real_fld_c = - |bound_ct, ty| *const_map.entry(bound_ct).or_insert_with(|| fld_c(bound_ct, ty)); - - let mut replacer = - BoundVarReplacer::new(self, &mut real_fld_r, &mut real_fld_t, &mut real_fld_c); - let result = value.fold_with(&mut replacer); - (result, region_map) - } - } - - /// Replaces all types or regions bound by the given `Binder`. The `fld_r` - /// closure replaces bound regions while the `fld_t` closure replaces bound - /// types. - pub fn replace_bound_vars<T, F, G, H>( - self, - value: &Binder<T>, - fld_r: F, - fld_t: G, - fld_c: H, - ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) - where - F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, - G: FnMut(ty::BoundTy) -> Ty<'tcx>, - H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, - T: TypeFoldable<'tcx>, - { - self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) - } - - /// Replaces any late-bound regions bound in `value` with - /// free variants attached to `all_outlive_scope`. - pub fn liberate_late_bound_regions<T>( - &self, - all_outlive_scope: DefId, - value: &ty::Binder<T>, - ) -> T - where - T: TypeFoldable<'tcx>, - { - self.replace_late_bound_regions(value, |br| { - self.mk_region(ty::ReFree(ty::FreeRegion { - scope: all_outlive_scope, - bound_region: br, - })) - }) - .0 - } - - /// Returns a set of all late-bound regions that are constrained - /// by `value`, meaning that if we instantiate those LBR with - /// variables and equate `value` with something else, those - /// variables will also be equated. - pub fn collect_constrained_late_bound_regions<T>( - &self, - value: &Binder<T>, - ) -> FxHashSet<ty::BoundRegion> - where - T: TypeFoldable<'tcx>, - { - self.collect_late_bound_regions(value, true) - } - - /// Returns a set of all late-bound regions that appear in `value` anywhere. - pub fn collect_referenced_late_bound_regions<T>( - &self, - value: &Binder<T>, - ) -> FxHashSet<ty::BoundRegion> - where - T: TypeFoldable<'tcx>, - { - self.collect_late_bound_regions(value, false) - } - - fn collect_late_bound_regions<T>( - &self, - value: &Binder<T>, - just_constraint: bool, - ) -> FxHashSet<ty::BoundRegion> - where - T: TypeFoldable<'tcx>, - { - let mut collector = LateBoundRegionsCollector::new(just_constraint); - let result = value.skip_binder().visit_with(&mut collector); - assert!(!result); // should never have stopped early - collector.regions - } - - /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also - /// method lookup and a few other places where precise region relationships are not required. - pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T - where - T: TypeFoldable<'tcx>, - { - self.replace_late_bound_regions(value, |_| self.lifetimes.re_erased).0 - } - - /// Rewrite any late-bound regions so that they are anonymous. Region numbers are - /// assigned starting at 1 and increasing monotonically in the order traversed - /// by the fold operation. - /// - /// The chief purpose of this function is to canonicalize regions so that two - /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become - /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and - /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization. - pub fn anonymize_late_bound_regions<T>(self, sig: &Binder<T>) -> Binder<T> - where - T: TypeFoldable<'tcx>, - { - let mut counter = 0; - Binder::bind( - self.replace_late_bound_regions(sig, |_| { - counter += 1; - self.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(counter))) - }) - .0, - ) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Shifter -// -// Shifts the De Bruijn indices on all escaping bound vars by a -// fixed amount. Useful in substitution or when otherwise introducing -// a binding level that is not intended to capture the existing bound -// vars. See comment on `shift_vars_through_binders` method in -// `subst.rs` for more details. - -enum Direction { - In, - Out, -} - -struct Shifter<'tcx> { - tcx: TyCtxt<'tcx>, - current_index: ty::DebruijnIndex, - amount: u32, - direction: Direction, -} - -impl Shifter<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, amount: u32, direction: Direction) -> Self { - Shifter { tcx, current_index: ty::INNERMOST, amount, direction } - } -} - -impl TypeFolder<'tcx> for Shifter<'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> { - self.current_index.shift_in(1); - let t = t.super_fold_with(self); - self.current_index.shift_out(1); - t - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - ty::ReLateBound(debruijn, br) => { - if self.amount == 0 || debruijn < self.current_index { - r - } else { - let debruijn = match self.direction { - Direction::In => debruijn.shifted_in(self.amount), - Direction::Out => { - assert!(debruijn.as_u32() >= self.amount); - debruijn.shifted_out(self.amount) - } - }; - let shifted = ty::ReLateBound(debruijn, br); - self.tcx.mk_region(shifted) - } - } - _ => r, - } - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { - ty::Bound(debruijn, bound_ty) => { - if self.amount == 0 || debruijn < self.current_index { - ty - } else { - let debruijn = match self.direction { - Direction::In => debruijn.shifted_in(self.amount), - Direction::Out => { - assert!(debruijn.as_u32() >= self.amount); - debruijn.shifted_out(self.amount) - } - }; - self.tcx.mk_ty(ty::Bound(debruijn, bound_ty)) - } - } - - _ => ty.super_fold_with(self), - } - } - - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty } = *ct { - if self.amount == 0 || debruijn < self.current_index { - ct - } else { - let debruijn = match self.direction { - Direction::In => debruijn.shifted_in(self.amount), - Direction::Out => { - assert!(debruijn.as_u32() >= self.amount); - debruijn.shifted_out(self.amount) - } - }; - self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty }) - } - } else { - ct.super_fold_with(self) - } - } -} - -pub fn shift_region<'tcx>( - tcx: TyCtxt<'tcx>, - region: ty::Region<'tcx>, - amount: u32, -) -> ty::Region<'tcx> { - match region { - ty::ReLateBound(debruijn, br) if amount > 0 => { - tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), *br)) - } - _ => region, - } -} - -pub fn shift_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: &T, amount: u32) -> T -where - T: TypeFoldable<'tcx>, -{ - debug!("shift_vars(value={:?}, amount={})", value, amount); - - value.fold_with(&mut Shifter::new(tcx, amount, Direction::In)) -} - -pub fn shift_out_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: &T, amount: u32) -> T -where - T: TypeFoldable<'tcx>, -{ - debug!("shift_out_vars(value={:?}, amount={})", value, amount); - - value.fold_with(&mut Shifter::new(tcx, amount, Direction::Out)) -} - -/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a -/// bound region or a bound type. -/// -/// So, for example, consider a type like the following, which has two binders: -/// -/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize)) -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope -/// -/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the -/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner -/// fn type*, that type has an escaping region: `'a`. -/// -/// Note that what I'm calling an "escaping var" is often just called a "free var". However, -/// we already use the term "free var". It refers to the regions or types that we use to represent -/// bound regions or type params on a fn definition while we are type checking its body. -/// -/// To clarify, conceptually there is no particular difference between -/// an "escaping" var and a "free" var. However, there is a big -/// difference in practice. Basically, when "entering" a binding -/// level, one is generally required to do some sort of processing to -/// a bound var, such as replacing it with a fresh/placeholder -/// var, or making an entry in the environment to represent the -/// scope to which it is attached, etc. An escaping var represents -/// a bound var for which this processing has not yet been done. -struct HasEscapingVarsVisitor { - /// Anything bound by `outer_index` or "above" is escaping. - outer_index: ty::DebruijnIndex, -} - -impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { - self.outer_index.shift_in(1); - let result = t.super_visit_with(self); - self.outer_index.shift_out(1); - result - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - // If the outer-exclusive-binder is *strictly greater* than - // `outer_index`, that means that `t` contains some content - // bound at `outer_index` or above (because - // `outer_exclusive_binder` is always 1 higher than the - // content in `t`). Therefore, `t` has some escaping vars. - t.outer_exclusive_binder > self.outer_index - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - // If the region is bound by `outer_index` or anything outside - // of outer index, then it escapes the binders we have - // visited. - r.bound_at_or_above_binder(self.outer_index) - } - - fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> bool { - // we don't have a `visit_infer_const` callback, so we have to - // hook in here to catch this case (annoying...), but - // otherwise we do want to remember to visit the rest of the - // const, as it has types/regions embedded in a lot of other - // places. - match ct.val { - ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => true, - _ => ct.super_visit_with(self), - } - } -} - -// FIXME: Optimize for checking for infer flags -struct HasTypeFlagsVisitor { - flags: ty::TypeFlags, -} - -impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { - fn visit_ty(&mut self, t: Ty<'_>) -> bool { - debug!("HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, t.flags, self.flags); - t.flags.intersects(self.flags) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - let flags = r.type_flags(); - debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); - flags.intersects(self.flags) - } - - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { - let flags = FlagComputation::for_const(c); - debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); - flags.intersects(self.flags) - } -} - -/// Collects all the late-bound regions at the innermost binding level -/// into a hash set. -struct LateBoundRegionsCollector { - current_index: ty::DebruijnIndex, - regions: FxHashSet<ty::BoundRegion>, - - /// `true` if we only want regions that are known to be - /// "constrained" when you equate this type with another type. In - /// particular, if you have e.g., `&'a u32` and `&'b u32`, equating - /// them constraints `'a == 'b`. But if you have `<&'a u32 as - /// Trait>::Foo` and `<&'b u32 as Trait>::Foo`, normalizing those - /// types may mean that `'a` and `'b` don't appear in the results, - /// so they are not considered *constrained*. - just_constrained: bool, -} - -impl LateBoundRegionsCollector { - fn new(just_constrained: bool) -> Self { - LateBoundRegionsCollector { - current_index: ty::INNERMOST, - regions: Default::default(), - just_constrained, - } - } -} - -impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { - self.current_index.shift_in(1); - let result = t.super_visit_with(self); - self.current_index.shift_out(1); - result - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - // if we are only looking for "constrained" region, we have to - // ignore the inputs to a projection, as they may not appear - // in the normalized form - if self.just_constrained { - match t.kind { - ty::Projection(..) | ty::Opaque(..) => { - return false; - } - _ => {} - } - } - - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - if let ty::ReLateBound(debruijn, br) = *r { - if debruijn == self.current_index { - self.regions.insert(br); - } - } - false - } -} diff --git a/src/librustc/ty/free_region_map.rs b/src/librustc/ty/free_region_map.rs deleted file mode 100644 index 2ab12a4acbf..00000000000 --- a/src/librustc/ty/free_region_map.rs +++ /dev/null @@ -1,133 +0,0 @@ -use crate::ty::{self, Lift, Region, TyCtxt}; -use rustc_data_structures::transitive_relation::TransitiveRelation; - -#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default, HashStable)] -pub struct FreeRegionMap<'tcx> { - // Stores the relation `a < b`, where `a` and `b` are regions. - // - // Invariant: only free regions like `'x` or `'static` are stored - // in this relation, not scopes. - relation: TransitiveRelation<Region<'tcx>>, -} - -impl<'tcx> FreeRegionMap<'tcx> { - pub fn elements(&self) -> impl Iterator<Item = &Region<'tcx>> { - self.relation.elements() - } - - pub fn is_empty(&self) -> bool { - self.relation.is_empty() - } - - // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`. - // (with the exception that `'static: 'x` is not notable) - pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) { - debug!("relate_regions(sub={:?}, sup={:?})", sub, sup); - if self.is_free_or_static(sub) && self.is_free(sup) { - self.relation.add(sub, sup) - } - } - - /// Tests whether `r_a <= r_b`. - /// - /// Both regions must meet `is_free_or_static`. - /// - /// Subtle: one tricky case that this code gets correct is as - /// follows. If we know that `r_b: 'static`, then this function - /// will return true, even though we don't know anything that - /// directly relates `r_a` and `r_b`. - /// - /// Also available through the `FreeRegionRelations` trait below. - pub fn sub_free_regions( - &self, - tcx: TyCtxt<'tcx>, - r_a: Region<'tcx>, - r_b: Region<'tcx>, - ) -> bool { - assert!(self.is_free_or_static(r_a) && self.is_free_or_static(r_b)); - let re_static = tcx.lifetimes.re_static; - if self.check_relation(re_static, r_b) { - // `'a <= 'static` is always true, and not stored in the - // relation explicitly, so check if `'b` is `'static` (or - // equivalent to it) - true - } else { - self.check_relation(r_a, r_b) - } - } - - /// Check whether `r_a <= r_b` is found in the relation. - fn check_relation(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool { - r_a == r_b || self.relation.contains(&r_a, &r_b) - } - - /// True for free regions other than `'static`. - pub fn is_free(&self, r: Region<'_>) -> bool { - match *r { - ty::ReEarlyBound(_) | ty::ReFree(_) => true, - _ => false, - } - } - - /// True if `r` is a free region or static of the sort that this - /// free region map can be used with. - pub fn is_free_or_static(&self, r: Region<'_>) -> bool { - match *r { - ty::ReStatic => true, - _ => self.is_free(r), - } - } - - /// Computes the least-upper-bound of two free regions. In some - /// cases, this is more conservative than necessary, in order to - /// avoid making arbitrary choices. See - /// `TransitiveRelation::postdom_upper_bound` for more details. - pub fn lub_free_regions( - &self, - tcx: TyCtxt<'tcx>, - r_a: Region<'tcx>, - r_b: Region<'tcx>, - ) -> Region<'tcx> { - debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b); - assert!(self.is_free(r_a)); - assert!(self.is_free(r_b)); - let result = if r_a == r_b { - r_a - } else { - match self.relation.postdom_upper_bound(&r_a, &r_b) { - None => tcx.lifetimes.re_static, - Some(r) => *r, - } - }; - debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result); - result - } -} - -/// The NLL region handling code represents free region relations in a -/// slightly different way; this trait allows functions to be abstract -/// over which version is in use. -pub trait FreeRegionRelations<'tcx> { - /// Tests whether `r_a <= r_b`. Both must be free regions or - /// `'static`. - fn sub_free_regions( - &self, - tcx: TyCtxt<'tcx>, - shorter: ty::Region<'tcx>, - longer: ty::Region<'tcx>, - ) -> bool; -} - -impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> { - fn sub_free_regions(&self, tcx: TyCtxt<'tcx>, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool { - // invoke the "inherent method" - self.sub_free_regions(tcx, r_a, r_b) - } -} - -impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> { - type Lifted = FreeRegionMap<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> { - self.relation.maybe_map(|&fr| tcx.lift(&fr)).map(|relation| FreeRegionMap { relation }) - } -} diff --git a/src/librustc/ty/inhabitedness/def_id_forest.rs b/src/librustc/ty/inhabitedness/def_id_forest.rs deleted file mode 100644 index 14ead77653c..00000000000 --- a/src/librustc/ty/inhabitedness/def_id_forest.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::ty::context::TyCtxt; -use crate::ty::{DefId, DefIdTree}; -use rustc_hir::CRATE_HIR_ID; -use smallvec::SmallVec; -use std::mem; - -/// Represents a forest of `DefId`s closed under the ancestor relation. That is, -/// if a `DefId` representing a module is contained in the forest then all -/// `DefId`s defined in that module or submodules are also implicitly contained -/// in the forest. -/// -/// This is used to represent a set of modules in which a type is visibly -/// uninhabited. -#[derive(Clone)] -pub struct DefIdForest { - /// The minimal set of `DefId`s required to represent the whole set. - /// If A and B are DefIds in the `DefIdForest`, and A is a descendant - /// of B, then only B will be in `root_ids`. - /// We use a `SmallVec` here because (for its use for caching inhabitedness) - /// its rare that this will contain even two IDs. - root_ids: SmallVec<[DefId; 1]>, -} - -impl<'tcx> DefIdForest { - /// Creates an empty forest. - pub fn empty() -> DefIdForest { - DefIdForest { root_ids: SmallVec::new() } - } - - /// Creates a forest consisting of a single tree representing the entire - /// crate. - #[inline] - pub fn full(tcx: TyCtxt<'tcx>) -> DefIdForest { - let crate_id = tcx.hir().local_def_id(CRATE_HIR_ID); - DefIdForest::from_id(crate_id) - } - - /// Creates a forest containing a `DefId` and all its descendants. - pub fn from_id(id: DefId) -> DefIdForest { - let mut root_ids = SmallVec::new(); - root_ids.push(id); - DefIdForest { root_ids } - } - - /// Tests whether the forest is empty. - pub fn is_empty(&self) -> bool { - self.root_ids.is_empty() - } - - /// Tests whether the forest contains a given DefId. - pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool { - self.root_ids.iter().any(|root_id| tcx.is_descendant_of(id, *root_id)) - } - - /// Calculate the intersection of a collection of forests. - pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest - where - I: IntoIterator<Item = DefIdForest>, - { - let mut iter = iter.into_iter(); - let mut ret = if let Some(first) = iter.next() { - first - } else { - return DefIdForest::full(tcx); - }; - - let mut next_ret = SmallVec::new(); - let mut old_ret: SmallVec<[DefId; 1]> = SmallVec::new(); - for next_forest in iter { - // No need to continue if the intersection is already empty. - if ret.is_empty() { - break; - } - - for id in ret.root_ids.drain(..) { - if next_forest.contains(tcx, id) { - next_ret.push(id); - } else { - old_ret.push(id); - } - } - ret.root_ids.extend(old_ret.drain(..)); - - next_ret.extend(next_forest.root_ids.into_iter().filter(|&id| ret.contains(tcx, id))); - - mem::swap(&mut next_ret, &mut ret.root_ids); - next_ret.drain(..); - } - ret - } - - /// Calculate the union of a collection of forests. - pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest - where - I: IntoIterator<Item = DefIdForest>, - { - let mut ret = DefIdForest::empty(); - let mut next_ret = SmallVec::new(); - for next_forest in iter { - next_ret.extend(ret.root_ids.drain(..).filter(|&id| !next_forest.contains(tcx, id))); - - for id in next_forest.root_ids { - if !next_ret.contains(&id) { - next_ret.push(id); - } - } - - mem::swap(&mut next_ret, &mut ret.root_ids); - next_ret.drain(..); - } - ret - } -} diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs deleted file mode 100644 index 144e3bc9c8b..00000000000 --- a/src/librustc/ty/inhabitedness/mod.rs +++ /dev/null @@ -1,206 +0,0 @@ -pub use self::def_id_forest::DefIdForest; - -use crate::ty; -use crate::ty::context::TyCtxt; -use crate::ty::TyKind::*; -use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef}; -use crate::ty::{AdtKind, Visibility}; -use crate::ty::{DefId, SubstsRef}; - -mod def_id_forest; - -// The methods in this module calculate `DefIdForest`s of modules in which a -// `AdtDef`/`VariantDef`/`FieldDef` is visibly uninhabited. -// -// # Example -// ```rust -// enum Void {} -// mod a { -// pub mod b { -// pub struct SecretlyUninhabited { -// _priv: !, -// } -// } -// } -// -// mod c { -// pub struct AlsoSecretlyUninhabited { -// _priv: Void, -// } -// mod d { -// } -// } -// -// struct Foo { -// x: a::b::SecretlyUninhabited, -// y: c::AlsoSecretlyUninhabited, -// } -// ``` -// In this code, the type `Foo` will only be visibly uninhabited inside the -// modules `b`, `c` and `d`. Calling `uninhabited_from` on `Foo` or its `AdtDef` will -// return the forest of modules {`b`, `c`->`d`} (represented in a `DefIdForest` by the -// set {`b`, `c`}). -// -// We need this information for pattern-matching on `Foo` or types that contain -// `Foo`. -// -// # Example -// ```rust -// let foo_result: Result<T, Foo> = ... ; -// let Ok(t) = foo_result; -// ``` -// This code should only compile in modules where the uninhabitedness of `Foo` is -// visible. - -impl<'tcx> TyCtxt<'tcx> { - /// Checks whether a type is visibly uninhabited from a particular module. - /// - /// # Example - /// ```rust - /// enum Void {} - /// mod a { - /// pub mod b { - /// pub struct SecretlyUninhabited { - /// _priv: !, - /// } - /// } - /// } - /// - /// mod c { - /// pub struct AlsoSecretlyUninhabited { - /// _priv: Void, - /// } - /// mod d { - /// } - /// } - /// - /// struct Foo { - /// x: a::b::SecretlyUninhabited, - /// y: c::AlsoSecretlyUninhabited, - /// } - /// ``` - /// In this code, the type `Foo` will only be visibly uninhabited inside the - /// modules b, c and d. This effects pattern-matching on `Foo` or types that - /// contain `Foo`. - /// - /// # Example - /// ```rust - /// let foo_result: Result<T, Foo> = ... ; - /// let Ok(t) = foo_result; - /// ``` - /// This code should only compile in modules where the uninhabitedness of Foo is - /// visible. - pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool { - // To check whether this type is uninhabited at all (not just from the - // given node), you could check whether the forest is empty. - // ``` - // forest.is_empty() - // ``` - ty.uninhabited_from(self).contains(self, module) - } - - pub fn is_ty_uninhabited_from_any_module(self, ty: Ty<'tcx>) -> bool { - !ty.uninhabited_from(self).is_empty() - } -} - -impl<'tcx> AdtDef { - /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited. - fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>) -> DefIdForest { - // Non-exhaustive ADTs from other crates are always considered inhabited. - if self.is_variant_list_non_exhaustive() && !self.did.is_local() { - DefIdForest::empty() - } else { - DefIdForest::intersection( - tcx, - self.variants.iter().map(|v| v.uninhabited_from(tcx, substs, self.adt_kind())), - ) - } - } -} - -impl<'tcx> VariantDef { - /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited. - pub fn uninhabited_from( - &self, - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - adt_kind: AdtKind, - ) -> DefIdForest { - let is_enum = match adt_kind { - // For now, `union`s are never considered uninhabited. - // The precise semantics of inhabitedness with respect to unions is currently undecided. - AdtKind::Union => return DefIdForest::empty(), - AdtKind::Enum => true, - AdtKind::Struct => false, - }; - // Non-exhaustive variants from other crates are always considered inhabited. - if self.is_field_list_non_exhaustive() && !self.def_id.is_local() { - DefIdForest::empty() - } else { - DefIdForest::union( - tcx, - self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum)), - ) - } - } -} - -impl<'tcx> FieldDef { - /// Calculates the forest of `DefId`s from which this field is visibly uninhabited. - fn uninhabited_from( - &self, - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - is_enum: bool, - ) -> DefIdForest { - let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx); - // FIXME(canndrew): Currently enum fields are (incorrectly) stored with - // `Visibility::Invisible` so we need to override `self.vis` if we're - // dealing with an enum. - if is_enum { - data_uninhabitedness() - } else { - match self.vis { - Visibility::Invisible => DefIdForest::empty(), - Visibility::Restricted(from) => { - let forest = DefIdForest::from_id(from); - let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness())); - DefIdForest::intersection(tcx, iter) - } - Visibility::Public => data_uninhabitedness(), - } - } - } -} - -impl<'tcx> TyS<'tcx> { - /// Calculates the forest of `DefId`s from which this type is visibly uninhabited. - fn uninhabited_from(&self, tcx: TyCtxt<'tcx>) -> DefIdForest { - match self.kind { - Adt(def, substs) => def.uninhabited_from(tcx, substs), - - Never => DefIdForest::full(tcx), - - Tuple(ref tys) => { - DefIdForest::union(tcx, tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx))) - } - - Array(ty, len) => match len.try_eval_usize(tcx, ty::ParamEnv::empty()) { - // If the array is definitely non-empty, it's uninhabited if - // the type of its elements is uninhabited. - Some(n) if n != 0 => ty.uninhabited_from(tcx), - _ => DefIdForest::empty(), - }, - - // References to uninitialised memory is valid for any type, including - // uninhabited types, in unsafe code, so we treat all references as - // inhabited. - // The precise semantics of inhabitedness with respect to references is currently - // undecided. - Ref(..) => DefIdForest::empty(), - - _ => DefIdForest::empty(), - } - } -} diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs deleted file mode 100644 index 66888cdb552..00000000000 --- a/src/librustc/ty/instance.rs +++ /dev/null @@ -1,428 +0,0 @@ -use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::middle::lang_items::DropInPlaceFnLangItem; -use crate::ty::print::{FmtPrinter, Printer}; -use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable}; -use rustc_data_structures::AtomicRef; -use rustc_hir::def::Namespace; -use rustc_hir::def_id::{CrateNum, DefId}; -use rustc_macros::HashStable; - -use std::fmt; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -#[derive(HashStable, Lift)] -pub struct Instance<'tcx> { - pub def: InstanceDef<'tcx>, - pub substs: SubstsRef<'tcx>, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub enum InstanceDef<'tcx> { - Item(DefId), - Intrinsic(DefId), - - /// `<T as Trait>::method` where `method` receives unsizeable `self: Self`. - VtableShim(DefId), - - /// `fn()` pointer where the function itself cannot be turned into a pointer. - /// - /// One example is `<dyn Trait as Trait>::fn`, where the shim contains - /// a virtual call, which codegen supports only via a direct call to the - /// `<dyn Trait as Trait>::fn` instance (an `InstanceDef::Virtual`). - /// - /// Another example is functions annotated with `#[track_caller]`, which - /// must have their implicit caller location argument populated for a call. - /// Because this is a required part of the function's ABI but can't be tracked - /// as a property of the function pointer, we use a single "caller location" - /// (the definition of the function itself). - ReifyShim(DefId), - - /// `<fn() as FnTrait>::call_*` - /// `DefId` is `FnTrait::call_*`. - FnPtrShim(DefId, Ty<'tcx>), - - /// `<dyn Trait as Trait>::fn`, "direct calls" of which are implicitly - /// codegen'd as virtual calls. - /// - /// NB: if this is reified to a `fn` pointer, a `ReifyShim` is used - /// (see `ReifyShim` above for more details on that). - Virtual(DefId, usize), - - /// `<[mut closure] as FnOnce>::call_once` - ClosureOnceShim { - call_once: DefId, - }, - - /// `core::ptr::drop_in_place::<T>`. - /// The `DefId` is for `core::ptr::drop_in_place`. - /// The `Option<Ty<'tcx>>` is either `Some(T)`, or `None` for empty drop - /// glue. - DropGlue(DefId, Option<Ty<'tcx>>), - - ///`<T as Clone>::clone` shim. - CloneShim(DefId, Ty<'tcx>), -} - -impl<'tcx> Instance<'tcx> { - /// Returns the `Ty` corresponding to this `Instance`, - /// with generic substitutions applied and lifetimes erased. - /// - /// This method can only be called when the 'substs' for this Instance - /// are fully monomorphic (no `ty::Param`'s are present). - /// This is usually the case (e.g. during codegen). - /// However, during constant evaluation, we may want - /// to try to resolve a `Instance` using generic parameters - /// (e.g. when we are attempting to to do const-propagation). - /// In this case, `Instance.ty_env` should be used to provide - /// the `ParamEnv` for our generic context. - pub fn monomorphic_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - let ty = tcx.type_of(self.def.def_id()); - // There shouldn't be any params - if there are, then - // Instance.ty_env should have been used to provide the proper - // ParamEnv - if self.substs.has_param_types() { - bug!("Instance.ty called for type {:?} with params in substs: {:?}", ty, self.substs); - } - tcx.subst_and_normalize_erasing_regions(self.substs, ty::ParamEnv::reveal_all(), &ty) - } - - /// Like `Instance.ty`, but allows a `ParamEnv` to be specified for use during - /// normalization. This method is only really useful during constant evaluation, - /// where we are dealing with potentially generic types. - pub fn ty_env(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> { - let ty = tcx.type_of(self.def.def_id()); - tcx.subst_and_normalize_erasing_regions(self.substs, param_env, &ty) - } - - /// Finds a crate that contains a monomorphization of this instance that - /// can be linked to from the local crate. A return value of `None` means - /// no upstream crate provides such an exported monomorphization. - /// - /// This method already takes into account the global `-Zshare-generics` - /// setting, always returning `None` if `share-generics` is off. - pub fn upstream_monomorphization(&self, tcx: TyCtxt<'tcx>) -> Option<CrateNum> { - // If we are not in share generics mode, we don't link to upstream - // monomorphizations but always instantiate our own internal versions - // instead. - if !tcx.sess.opts.share_generics() { - return None; - } - - // If this is an item that is defined in the local crate, no upstream - // crate can know about it/provide a monomorphization. - if self.def_id().is_local() { - return None; - } - - // If this a non-generic instance, it cannot be a shared monomorphization. - if self.substs.non_erasable_generics().next().is_none() { - return None; - } - - match self.def { - InstanceDef::Item(def_id) => tcx - .upstream_monomorphizations_for(def_id) - .and_then(|monos| monos.get(&self.substs).cloned()), - InstanceDef::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.substs), - _ => None, - } - } -} - -impl<'tcx> InstanceDef<'tcx> { - #[inline] - pub fn def_id(&self) -> DefId { - match *self { - InstanceDef::Item(def_id) - | InstanceDef::VtableShim(def_id) - | InstanceDef::ReifyShim(def_id) - | InstanceDef::FnPtrShim(def_id, _) - | InstanceDef::Virtual(def_id, _) - | InstanceDef::Intrinsic(def_id) - | InstanceDef::ClosureOnceShim { call_once: def_id } - | InstanceDef::DropGlue(def_id, _) - | InstanceDef::CloneShim(def_id, _) => def_id, - } - } - - #[inline] - pub fn attrs(&self, tcx: TyCtxt<'tcx>) -> ty::Attributes<'tcx> { - tcx.get_attrs(self.def_id()) - } - - /// Returns `true` if the LLVM version of this instance is unconditionally - /// marked with `inline`. This implies that a copy of this instance is - /// generated in every codegen unit. - /// Note that this is only a hint. See the documentation for - /// `generates_cgu_internal_copy` for more information. - pub fn requires_inline(&self, tcx: TyCtxt<'tcx>) -> bool { - use crate::hir::map::DefPathData; - let def_id = match *self { - ty::InstanceDef::Item(def_id) => def_id, - ty::InstanceDef::DropGlue(_, Some(_)) => return false, - _ => return true, - }; - match tcx.def_key(def_id).disambiguated_data.data { - DefPathData::Ctor | DefPathData::ClosureExpr => true, - _ => false, - } - } - - /// Returns `true` if the machine code for this instance is instantiated in - /// each codegen unit that references it. - /// Note that this is only a hint! The compiler can globally decide to *not* - /// do this in order to speed up compilation. CGU-internal copies are - /// only exist to enable inlining. If inlining is not performed (e.g. at - /// `-Copt-level=0`) then the time for generating them is wasted and it's - /// better to create a single copy with external linkage. - pub fn generates_cgu_internal_copy(&self, tcx: TyCtxt<'tcx>) -> bool { - if self.requires_inline(tcx) { - return true; - } - if let ty::InstanceDef::DropGlue(.., Some(ty)) = *self { - // Drop glue generally wants to be instantiated at every codegen - // unit, but without an #[inline] hint. We should make this - // available to normal end-users. - if tcx.sess.opts.incremental.is_none() { - return true; - } - // When compiling with incremental, we can generate a *lot* of - // codegen units. Including drop glue into all of them has a - // considerable compile time cost. - // - // We include enums without destructors to allow, say, optimizing - // drops of `Option::None` before LTO. We also respect the intent of - // `#[inline]` on `Drop::drop` implementations. - return ty.ty_adt_def().map_or(true, |adt_def| { - adt_def.destructor(tcx).map_or(adt_def.is_enum(), |dtor| { - tcx.codegen_fn_attrs(dtor.did).requests_inline() - }) - }); - } - tcx.codegen_fn_attrs(self.def_id()).requests_inline() - } - - pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool { - match *self { - InstanceDef::Item(def_id) => { - tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER) - } - _ => false, - } - } -} - -impl<'tcx> fmt::Display for Instance<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ty::tls::with(|tcx| { - let substs = tcx.lift(&self.substs).expect("could not lift for printing"); - FmtPrinter::new(tcx, &mut *f, Namespace::ValueNS) - .print_def_path(self.def_id(), substs)?; - Ok(()) - })?; - - match self.def { - InstanceDef::Item(_) => Ok(()), - InstanceDef::VtableShim(_) => write!(f, " - shim(vtable)"), - InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"), - InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), - InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num), - InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({:?})", ty), - InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"), - InstanceDef::DropGlue(_, ty) => write!(f, " - shim({:?})", ty), - InstanceDef::CloneShim(_, ty) => write!(f, " - shim({:?})", ty), - } - } -} - -impl<'tcx> Instance<'tcx> { - pub fn new(def_id: DefId, substs: SubstsRef<'tcx>) -> Instance<'tcx> { - assert!( - !substs.has_escaping_bound_vars(), - "substs of instance {:?} not normalized for codegen: {:?}", - def_id, - substs - ); - Instance { def: InstanceDef::Item(def_id), substs: substs } - } - - pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { - Instance::new(def_id, tcx.empty_substs_for_def_id(def_id)) - } - - #[inline] - pub fn def_id(&self) -> DefId { - self.def.def_id() - } - - /// Resolves a `(def_id, substs)` pair to an (optional) instance -- most commonly, - /// this is used to find the precise code that will run for a trait method invocation, - /// if known. - /// - /// Returns `None` if we cannot resolve `Instance` to a specific instance. - /// For example, in a context like this, - /// - /// ``` - /// fn foo<T: Debug>(t: T) { ... } - /// ``` - /// - /// trying to resolve `Debug::fmt` applied to `T` will yield `None`, because we do not - /// know what code ought to run. (Note that this setting is also affected by the - /// `RevealMode` in the parameter environment.) - /// - /// Presuming that coherence and type-check have succeeded, if this method is invoked - /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return - /// `Some`. - pub fn resolve( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> Option<Instance<'tcx>> { - (*RESOLVE_INSTANCE)(tcx, param_env, def_id, substs) - } - - pub fn resolve_for_fn_ptr( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> Option<Instance<'tcx>> { - debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); - Instance::resolve(tcx, param_env, def_id, substs).map(|mut resolved| { - match resolved.def { - InstanceDef::Item(def_id) if resolved.def.requires_caller_location(tcx) => { - debug!(" => fn pointer created for function with #[track_caller]"); - resolved.def = InstanceDef::ReifyShim(def_id); - } - InstanceDef::Virtual(def_id, _) => { - debug!(" => fn pointer created for virtual call"); - resolved.def = InstanceDef::ReifyShim(def_id); - } - _ => {} - } - - resolved - }) - } - - pub fn resolve_for_vtable( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> Option<Instance<'tcx>> { - debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); - let fn_sig = tcx.fn_sig(def_id); - let is_vtable_shim = fn_sig.inputs().skip_binder().len() > 0 - && fn_sig.input(0).skip_binder().is_param(0) - && tcx.generics_of(def_id).has_self; - if is_vtable_shim { - debug!(" => associated item with unsizeable self: Self"); - Some(Instance { def: InstanceDef::VtableShim(def_id), substs }) - } else { - Instance::resolve(tcx, param_env, def_id, substs) - } - } - - pub fn resolve_closure( - tcx: TyCtxt<'tcx>, - def_id: DefId, - substs: ty::SubstsRef<'tcx>, - requested_kind: ty::ClosureKind, - ) -> Instance<'tcx> { - let actual_kind = substs.as_closure().kind(def_id, tcx); - - match needs_fn_once_adapter_shim(actual_kind, requested_kind) { - Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, substs), - _ => Instance::new(def_id, substs), - } - } - - pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(DropInPlaceFnLangItem, None); - let substs = tcx.intern_substs(&[ty.into()]); - Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap() - } - - pub fn fn_once_adapter_instance( - tcx: TyCtxt<'tcx>, - closure_did: DefId, - substs: ty::SubstsRef<'tcx>, - ) -> Instance<'tcx> { - debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, substs); - let fn_once = tcx.lang_items().fn_once_trait().unwrap(); - let call_once = tcx - .associated_items(fn_once) - .in_definition_order() - .find(|it| it.kind == ty::AssocKind::Method) - .unwrap() - .def_id; - let def = ty::InstanceDef::ClosureOnceShim { call_once }; - - let self_ty = tcx.mk_closure(closure_did, substs); - - let sig = substs.as_closure().sig(closure_did, tcx); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - assert_eq!(sig.inputs().len(), 1); - let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]); - - debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); - Instance { def, substs } - } - - pub fn is_vtable_shim(&self) -> bool { - if let InstanceDef::VtableShim(..) = self.def { true } else { false } - } -} - -fn needs_fn_once_adapter_shim( - actual_closure_kind: ty::ClosureKind, - trait_closure_kind: ty::ClosureKind, -) -> Result<bool, ()> { - match (actual_closure_kind, trait_closure_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) - | (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) - | (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { - // No adapter needed. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { - // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at codegen time, these are - // basically the same thing, so we can just return llfn. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) - | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut - // self, ...)`. We want a `fn(self, ...)`. We can produce - // this by doing something like: - // - // fn call_once(self, ...) { call_mut(&self, ...) } - // fn call_once(mut self, ...) { call_mut(&mut self, ...) } - // - // These are both the same at codegen time. - Ok(true) - } - (ty::ClosureKind::FnMut, _) | (ty::ClosureKind::FnOnce, _) => Err(()), - } -} - -fn resolve_instance_default( - _tcx: TyCtxt<'tcx>, - _param_env: ty::ParamEnv<'tcx>, - _def_id: DefId, - _substs: SubstsRef<'tcx>, -) -> Option<Instance<'tcx>> { - unimplemented!() -} - -pub static RESOLVE_INSTANCE: AtomicRef< - for<'tcx> fn( - TyCtxt<'tcx>, - ty::ParamEnv<'tcx>, - DefId, - SubstsRef<'tcx>, - ) -> Option<Instance<'tcx>>, -> = AtomicRef::new(&(resolve_instance_default as _)); diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs deleted file mode 100644 index e8bf2eb9a12..00000000000 --- a/src/librustc/ty/layout.rs +++ /dev/null @@ -1,2744 +0,0 @@ -use crate::session::{self, DataTypeKind}; -use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable}; - -use rustc_attr as attr; -use rustc_span::DUMMY_SP; -use syntax::ast::{self, Ident, IntTy, UintTy}; - -use std::cmp; -use std::fmt; -use std::i128; -use std::iter; -use std::mem; -use std::ops::Bound; - -use crate::ich::StableHashingContext; -use crate::mir::{GeneratorLayout, GeneratorSavedLocal}; -use crate::ty::subst::Subst; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir as hir; -use rustc_index::bit_set::BitSet; -use rustc_index::vec::{Idx, IndexVec}; - -use rustc_target::abi::call::{ - ArgAbi, ArgAttribute, ArgAttributes, Conv, FnAbi, PassMode, Reg, RegKind, -}; -pub use rustc_target::abi::*; -use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec}; - -pub trait IntegerExt { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>; - fn from_attr<C: HasDataLayout>(cx: &C, ity: attr::IntType) -> Integer; - fn repr_discr<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - repr: &ReprOptions, - min: i128, - max: i128, - ) -> (Integer, bool); -} - -impl IntegerExt for Integer { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> { - match (*self, signed) { - (I8, false) => tcx.types.u8, - (I16, false) => tcx.types.u16, - (I32, false) => tcx.types.u32, - (I64, false) => tcx.types.u64, - (I128, false) => tcx.types.u128, - (I8, true) => tcx.types.i8, - (I16, true) => tcx.types.i16, - (I32, true) => tcx.types.i32, - (I64, true) => tcx.types.i64, - (I128, true) => tcx.types.i128, - } - } - - /// Gets the Integer type from an attr::IntType. - fn from_attr<C: HasDataLayout>(cx: &C, ity: attr::IntType) -> Integer { - let dl = cx.data_layout(); - - match ity { - attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8, - attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16, - attr::SignedInt(IntTy::I32) | attr::UnsignedInt(UintTy::U32) => I32, - attr::SignedInt(IntTy::I64) | attr::UnsignedInt(UintTy::U64) => I64, - attr::SignedInt(IntTy::I128) | attr::UnsignedInt(UintTy::U128) => I128, - attr::SignedInt(IntTy::Isize) | attr::UnsignedInt(UintTy::Usize) => { - dl.ptr_sized_integer() - } - } - } - - /// Finds the appropriate Integer type and signedness for the given - /// signed discriminant range and #[repr] attribute. - /// N.B.: u128 values above i128::MAX will be treated as signed, but - /// that shouldn't affect anything, other than maybe debuginfo. - fn repr_discr<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - repr: &ReprOptions, - min: i128, - max: i128, - ) -> (Integer, bool) { - // Theoretically, negative values could be larger in unsigned representation - // than the unsigned representation of the signed minimum. However, if there - // are any negative values, the only valid unsigned representation is u128 - // which can fit all i128 values, so the result remains unaffected. - let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128)); - let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max)); - - let mut min_from_extern = None; - let min_default = I8; - - if let Some(ity) = repr.int { - let discr = Integer::from_attr(&tcx, ity); - let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; - if discr < fit { - bug!( - "Integer::repr_discr: `#[repr]` hint too small for \ - discriminant range of enum `{}", - ty - ) - } - return (discr, ity.is_signed()); - } - - if repr.c() { - match &tcx.sess.target.target.arch[..] { - // WARNING: the ARM EABI has two variants; the one corresponding - // to `at_least == I32` appears to be used on Linux and NetBSD, - // but some systems may use the variant corresponding to no - // lower bound. However, we don't run on those yet...? - "arm" => min_from_extern = Some(I32), - _ => min_from_extern = Some(I32), - } - } - - let at_least = min_from_extern.unwrap_or(min_default); - - // If there are no negative values, we can use the unsigned fit. - if min >= 0 { - (cmp::max(unsigned_fit, at_least), false) - } else { - (cmp::max(signed_fit, at_least), true) - } - } -} - -pub trait PrimitiveExt { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; - fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; -} - -impl PrimitiveExt for Primitive { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match *self { - Int(i, signed) => i.to_ty(tcx, signed), - F32 => tcx.types.f32, - F64 => tcx.types.f64, - Pointer => tcx.mk_mut_ptr(tcx.mk_unit()), - } - } - - /// Return an *integer* type matching this primitive. - /// Useful in particular when dealing with enum discriminants. - fn to_int_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match *self { - Int(i, signed) => i.to_ty(tcx, signed), - Pointer => tcx.types.usize, - F32 | F64 => bug!("floats do not have an int type"), - } - } -} - -/// The first half of a fat pointer. -/// -/// - For a trait object, this is the address of the box. -/// - For a slice, this is the base address. -pub const FAT_PTR_ADDR: usize = 0; - -/// The second half of a fat pointer. -/// -/// - For a trait object, this is the address of the vtable. -/// - For a slice, this is the length. -pub const FAT_PTR_EXTRA: usize = 1; - -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] -pub enum LayoutError<'tcx> { - Unknown(Ty<'tcx>), - SizeOverflow(Ty<'tcx>), -} - -impl<'tcx> fmt::Display for LayoutError<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - LayoutError::Unknown(ty) => write!(f, "the type `{:?}` has an unknown layout", ty), - LayoutError::SizeOverflow(ty) => { - write!(f, "the type `{:?}` is too big for the current architecture", ty) - } - } - } -} - -fn layout_raw<'tcx>( - tcx: TyCtxt<'tcx>, - query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, -) -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> { - ty::tls::with_related_context(tcx, move |icx| { - let rec_limit = *tcx.sess.recursion_limit.get(); - let (param_env, ty) = query.into_parts(); - - if icx.layout_depth > rec_limit { - tcx.sess.fatal(&format!("overflow representing the type `{}`", ty)); - } - - // Update the ImplicitCtxt to increase the layout_depth - let icx = ty::tls::ImplicitCtxt { layout_depth: icx.layout_depth + 1, ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| { - let cx = LayoutCx { tcx, param_env }; - let layout = cx.layout_raw_uncached(ty); - // Type-level uninhabitedness should always imply ABI uninhabitedness. - if let Ok(layout) = layout { - if ty.conservative_is_privately_uninhabited(tcx) { - assert!(layout.abi.is_uninhabited()); - } - } - layout - }) - }) -} - -pub fn provide(providers: &mut ty::query::Providers<'_>) { - *providers = ty::query::Providers { layout_raw, ..*providers }; -} - -pub struct LayoutCx<'tcx, C> { - pub tcx: C, - pub param_env: ty::ParamEnv<'tcx>, -} - -#[derive(Copy, Clone, Debug)] -enum StructKind { - /// A tuple, closure, or univariant which cannot be coerced to unsized. - AlwaysSized, - /// A univariant, the last field of which may be coerced to unsized. - MaybeUnsized, - /// A univariant, but with a prefix of an arbitrary size & alignment (e.g., enum tag). - Prefixed(Size, Align), -} - -// Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`. -// This is used to go between `memory_index` (source field order to memory order) -// and `inverse_memory_index` (memory order to source field order). -// See also `FieldPlacement::Arbitrary::memory_index` for more details. -// FIXME(eddyb) build a better abstraction for permutations, if possible. -fn invert_mapping(map: &[u32]) -> Vec<u32> { - let mut inverse = vec![0; map.len()]; - for i in 0..map.len() { - inverse[map[i] as usize] = i as u32; - } - inverse -} - -impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { - fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutDetails { - let dl = self.data_layout(); - let b_align = b.value.align(dl); - let align = a.value.align(dl).max(b_align).max(dl.aggregate_align); - let b_offset = a.value.size(dl).align_to(b_align.abi); - let size = (b_offset + b.value.size(dl)).align_to(align.abi); - - // HACK(nox): We iter on `b` and then `a` because `max_by_key` - // returns the last maximum. - let largest_niche = Niche::from_scalar(dl, b_offset, b.clone()) - .into_iter() - .chain(Niche::from_scalar(dl, Size::ZERO, a.clone())) - .max_by_key(|niche| niche.available(dl)); - - LayoutDetails { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Arbitrary { - offsets: vec![Size::ZERO, b_offset], - memory_index: vec![0, 1], - }, - abi: Abi::ScalarPair(a, b), - largest_niche, - align, - size, - } - } - - fn univariant_uninterned( - &self, - ty: Ty<'tcx>, - fields: &[TyLayout<'_>], - repr: &ReprOptions, - kind: StructKind, - ) -> Result<LayoutDetails, LayoutError<'tcx>> { - let dl = self.data_layout(); - let pack = repr.pack; - if pack.is_some() && repr.align.is_some() { - bug!("struct cannot be packed and aligned"); - } - - let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; - - let mut sized = true; - let mut offsets = vec![Size::ZERO; fields.len()]; - let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect(); - - let mut optimize = !repr.inhibit_struct_field_reordering_opt(); - if let StructKind::Prefixed(_, align) = kind { - optimize &= align.bytes() == 1; - } - - if optimize { - let end = - if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; - let optimizing = &mut inverse_memory_index[..end]; - let field_align = |f: &TyLayout<'_>| { - if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi } - }; - match kind { - StructKind::AlwaysSized | StructKind::MaybeUnsized => { - optimizing.sort_by_key(|&x| { - // Place ZSTs first to avoid "interesting offsets", - // especially with only one or two non-ZST fields. - let f = &fields[x as usize]; - (!f.is_zst(), cmp::Reverse(field_align(f))) - }); - } - StructKind::Prefixed(..) => { - optimizing.sort_by_key(|&x| field_align(&fields[x as usize])); - } - } - } - - // inverse_memory_index holds field indices by increasing memory offset. - // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5. - // We now write field offsets to the corresponding offset slot; - // field 5 with offset 0 puts 0 in offsets[5]. - // At the bottom of this function, we invert `inverse_memory_index` to - // produce `memory_index` (see `invert_mapping`). - - let mut offset = Size::ZERO; - let mut largest_niche = None; - let mut largest_niche_available = 0; - - if let StructKind::Prefixed(prefix_size, prefix_align) = kind { - let prefix_align = - if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align }; - align = align.max(AbiAndPrefAlign::new(prefix_align)); - offset = prefix_size.align_to(prefix_align); - } - - for &i in &inverse_memory_index { - let field = fields[i as usize]; - if !sized { - bug!("univariant: field #{} of `{}` comes after unsized field", offsets.len(), ty); - } - - if field.is_unsized() { - sized = false; - } - - // Invariant: offset < dl.obj_size_bound() <= 1<<61 - let field_align = if let Some(pack) = pack { - field.align.min(AbiAndPrefAlign::new(pack)) - } else { - field.align - }; - offset = offset.align_to(field_align.abi); - align = align.max(field_align); - - debug!("univariant offset: {:?} field: {:#?}", offset, field); - offsets[i as usize] = offset; - - if !repr.hide_niche() { - if let Some(mut niche) = field.largest_niche.clone() { - let available = niche.available(dl); - if available > largest_niche_available { - largest_niche_available = available; - niche.offset += offset; - largest_niche = Some(niche); - } - } - } - - offset = offset.checked_add(field.size, dl).ok_or(LayoutError::SizeOverflow(ty))?; - } - - if let Some(repr_align) = repr.align { - align = align.max(AbiAndPrefAlign::new(repr_align)); - } - - debug!("univariant min_size: {:?}", offset); - let min_size = offset; - - // As stated above, inverse_memory_index holds field indices by increasing offset. - // This makes it an already-sorted view of the offsets vec. - // To invert it, consider: - // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0. - // Field 5 would be the first element, so memory_index is i: - // Note: if we didn't optimize, it's already right. - - let memory_index; - if optimize { - memory_index = invert_mapping(&inverse_memory_index); - } else { - memory_index = inverse_memory_index; - } - - let size = min_size.align_to(align.abi); - let mut abi = Abi::Aggregate { sized }; - - // Unpack newtype ABIs and find scalar pairs. - if sized && size.bytes() > 0 { - // All other fields must be ZSTs, and we need them to all start at 0. - let mut zst_offsets = offsets.iter().enumerate().filter(|&(i, _)| fields[i].is_zst()); - if zst_offsets.all(|(_, o)| o.bytes() == 0) { - let mut non_zst_fields = fields.iter().enumerate().filter(|&(_, f)| !f.is_zst()); - - match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { - // We have exactly one non-ZST field. - (Some((i, field)), None, None) => { - // Field fills the struct and it has a scalar or scalar pair ABI. - if offsets[i].bytes() == 0 - && align.abi == field.align.abi - && size == field.size - { - match field.abi { - // For plain scalars, or vectors of them, we can't unpack - // newtypes for `#[repr(C)]`, as that affects C ABIs. - Abi::Scalar(_) | Abi::Vector { .. } if optimize => { - abi = field.abi.clone(); - } - // But scalar pairs are Rust-specific and get - // treated as aggregates by C ABIs anyway. - Abi::ScalarPair(..) => { - abi = field.abi.clone(); - } - _ => {} - } - } - } - - // Two non-ZST fields, and they're both scalars. - ( - Some(( - i, - &TyLayout { - details: &LayoutDetails { abi: Abi::Scalar(ref a), .. }, - .. - }, - )), - Some(( - j, - &TyLayout { - details: &LayoutDetails { abi: Abi::Scalar(ref b), .. }, - .. - }, - )), - None, - ) => { - // Order by the memory placement, not source order. - let ((i, a), (j, b)) = if offsets[i] < offsets[j] { - ((i, a), (j, b)) - } else { - ((j, b), (i, a)) - }; - let pair = self.scalar_pair(a.clone(), b.clone()); - let pair_offsets = match pair.fields { - FieldPlacement::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index, &[0, 1]); - offsets - } - _ => bug!(), - }; - if offsets[i] == pair_offsets[0] - && offsets[j] == pair_offsets[1] - && align == pair.align - && size == pair.size - { - // We can use `ScalarPair` only when it matches our - // already computed layout (including `#[repr(C)]`). - abi = pair.abi; - } - } - - _ => {} - } - } - } - - if sized && fields.iter().any(|f| f.abi.is_uninhabited()) { - abi = Abi::Uninhabited; - } - - Ok(LayoutDetails { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Arbitrary { offsets, memory_index }, - abi, - largest_niche, - align, - size, - }) - } - - fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> { - let tcx = self.tcx; - let param_env = self.param_env; - let dl = self.data_layout(); - let scalar_unit = |value: Primitive| { - let bits = value.size(dl).bits(); - assert!(bits <= 128); - Scalar { value, valid_range: 0..=(!0 >> (128 - bits)) } - }; - let scalar = - |value: Primitive| tcx.intern_layout(LayoutDetails::scalar(self, scalar_unit(value))); - - let univariant = |fields: &[TyLayout<'_>], repr: &ReprOptions, kind| { - Ok(tcx.intern_layout(self.univariant_uninterned(ty, fields, repr, kind)?)) - }; - debug_assert!(!ty.has_infer_types()); - - Ok(match ty.kind { - // Basic scalars. - ty::Bool => tcx.intern_layout(LayoutDetails::scalar( - self, - Scalar { value: Int(I8, false), valid_range: 0..=1 }, - )), - ty::Char => tcx.intern_layout(LayoutDetails::scalar( - self, - Scalar { value: Int(I32, false), valid_range: 0..=0x10FFFF }, - )), - ty::Int(ity) => scalar(Int(Integer::from_attr(dl, attr::SignedInt(ity)), true)), - ty::Uint(ity) => scalar(Int(Integer::from_attr(dl, attr::UnsignedInt(ity)), false)), - ty::Float(fty) => scalar(match fty { - ast::FloatTy::F32 => F32, - ast::FloatTy::F64 => F64, - }), - ty::FnPtr(_) => { - let mut ptr = scalar_unit(Pointer); - ptr.valid_range = 1..=*ptr.valid_range.end(); - tcx.intern_layout(LayoutDetails::scalar(self, ptr)) - } - - // The never type. - ty::Never => tcx.intern_layout(LayoutDetails { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Union(0), - abi: Abi::Uninhabited, - largest_niche: None, - align: dl.i8_align, - size: Size::ZERO, - }), - - // Potentially-fat pointers. - ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - let mut data_ptr = scalar_unit(Pointer); - if !ty.is_unsafe_ptr() { - data_ptr.valid_range = 1..=*data_ptr.valid_range.end(); - } - - let pointee = tcx.normalize_erasing_regions(param_env, pointee); - if pointee.is_sized(tcx.at(DUMMY_SP), param_env) { - return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr))); - } - - let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env); - let metadata = match unsized_part.kind { - ty::Foreign(..) => { - return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr))); - } - ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)), - ty::Dynamic(..) => { - let mut vtable = scalar_unit(Pointer); - vtable.valid_range = 1..=*vtable.valid_range.end(); - vtable - } - _ => return Err(LayoutError::Unknown(unsized_part)), - }; - - // Effectively a (ptr, meta) tuple. - tcx.intern_layout(self.scalar_pair(data_ptr, metadata)) - } - - // Arrays and slices. - ty::Array(element, mut count) => { - if count.has_projections() { - count = tcx.normalize_erasing_regions(param_env, count); - if count.has_projections() { - return Err(LayoutError::Unknown(ty)); - } - } - - let count = count.try_eval_usize(tcx, param_env).ok_or(LayoutError::Unknown(ty))?; - let element = self.layout_of(element)?; - let size = - element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?; - - let abi = if count != 0 && ty.conservative_is_privately_uninhabited(tcx) { - Abi::Uninhabited - } else { - Abi::Aggregate { sized: true } - }; - - let largest_niche = if count != 0 { element.largest_niche.clone() } else { None }; - - tcx.intern_layout(LayoutDetails { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Array { stride: element.size, count }, - abi, - largest_niche, - align: element.align, - size, - }) - } - ty::Slice(element) => { - let element = self.layout_of(element)?; - tcx.intern_layout(LayoutDetails { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Array { stride: element.size, count: 0 }, - abi: Abi::Aggregate { sized: false }, - largest_niche: None, - align: element.align, - size: Size::ZERO, - }) - } - ty::Str => tcx.intern_layout(LayoutDetails { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Array { stride: Size::from_bytes(1), count: 0 }, - abi: Abi::Aggregate { sized: false }, - largest_niche: None, - align: dl.i8_align, - size: Size::ZERO, - }), - - // Odd unit types. - ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?, - ty::Dynamic(..) | ty::Foreign(..) => { - let mut unit = self.univariant_uninterned( - ty, - &[], - &ReprOptions::default(), - StructKind::AlwaysSized, - )?; - match unit.abi { - Abi::Aggregate { ref mut sized } => *sized = false, - _ => bug!(), - } - tcx.intern_layout(unit) - } - - ty::Generator(def_id, substs, _) => self.generator_layout(ty, def_id, substs)?, - - ty::Closure(def_id, ref substs) => { - let tys = substs.as_closure().upvar_tys(def_id, tcx); - univariant( - &tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?, - &ReprOptions::default(), - StructKind::AlwaysSized, - )? - } - - ty::Tuple(tys) => { - let kind = - if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; - - univariant( - &tys.iter() - .map(|k| self.layout_of(k.expect_ty())) - .collect::<Result<Vec<_>, _>>()?, - &ReprOptions::default(), - kind, - )? - } - - // SIMD vector types. - ty::Adt(def, ..) if def.repr.simd() => { - let element = self.layout_of(ty.simd_type(tcx))?; - let count = ty.simd_size(tcx); - assert!(count > 0); - let scalar = match element.abi { - Abi::Scalar(ref scalar) => scalar.clone(), - _ => { - tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - ty, element.ty - )); - } - }; - let size = - element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?; - let align = dl.vector_align(size); - let size = size.align_to(align.abi); - - tcx.intern_layout(LayoutDetails { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldPlacement::Array { stride: element.size, count }, - abi: Abi::Vector { element: scalar, count }, - largest_niche: element.largest_niche.clone(), - size, - align, - }) - } - - // ADTs. - ty::Adt(def, substs) => { - // Cache the field layouts. - let variants = def - .variants - .iter() - .map(|v| { - v.fields - .iter() - .map(|field| self.layout_of(field.ty(tcx, substs))) - .collect::<Result<Vec<_>, _>>() - }) - .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; - - if def.is_union() { - if def.repr.pack.is_some() && def.repr.align.is_some() { - bug!("union cannot be packed and aligned"); - } - - let mut align = - if def.repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align }; - - if let Some(repr_align) = def.repr.align { - align = align.max(AbiAndPrefAlign::new(repr_align)); - } - - let optimize = !def.repr.inhibit_union_abi_opt(); - let mut size = Size::ZERO; - let mut abi = Abi::Aggregate { sized: true }; - let index = VariantIdx::new(0); - for field in &variants[index] { - assert!(!field.is_unsized()); - align = align.max(field.align); - - // If all non-ZST fields have the same ABI, forward this ABI - if optimize && !field.is_zst() { - // Normalize scalar_unit to the maximal valid range - let field_abi = match &field.abi { - Abi::Scalar(x) => Abi::Scalar(scalar_unit(x.value)), - Abi::ScalarPair(x, y) => { - Abi::ScalarPair(scalar_unit(x.value), scalar_unit(y.value)) - } - Abi::Vector { element: x, count } => { - Abi::Vector { element: scalar_unit(x.value), count: *count } - } - Abi::Uninhabited | Abi::Aggregate { .. } => { - Abi::Aggregate { sized: true } - } - }; - - if size == Size::ZERO { - // first non ZST: initialize 'abi' - abi = field_abi; - } else if abi != field_abi { - // different fields have different ABI: reset to Aggregate - abi = Abi::Aggregate { sized: true }; - } - } - - size = cmp::max(size, field.size); - } - - if let Some(pack) = def.repr.pack { - align = align.min(AbiAndPrefAlign::new(pack)); - } - - return Ok(tcx.intern_layout(LayoutDetails { - variants: Variants::Single { index }, - fields: FieldPlacement::Union(variants[index].len()), - abi, - largest_niche: None, - align, - size: size.align_to(align.abi), - })); - } - - // A variant is absent if it's uninhabited and only has ZST fields. - // Present uninhabited variants only require space for their fields, - // but *not* an encoding of the discriminant (e.g., a tag value). - // See issue #49298 for more details on the need to leave space - // for non-ZST uninhabited data (mostly partial initialization). - let absent = |fields: &[TyLayout<'_>]| { - let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited()); - let is_zst = fields.iter().all(|f| f.is_zst()); - uninhabited && is_zst - }; - let (present_first, present_second) = { - let mut present_variants = variants - .iter_enumerated() - .filter_map(|(i, v)| if absent(v) { None } else { Some(i) }); - (present_variants.next(), present_variants.next()) - }; - let present_first = match present_first { - present_first @ Some(_) => present_first, - // Uninhabited because it has no variants, or only absent ones. - None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)), - // if it's a struct, still compute a layout so that we can still compute the - // field offsets - None => Some(VariantIdx::new(0)), - }; - - let is_struct = !def.is_enum() || - // Only one variant is present. - (present_second.is_none() && - // Representation optimizations are allowed. - !def.repr.inhibit_enum_layout_opt()); - if is_struct { - // Struct, or univariant enum equivalent to a struct. - // (Typechecking will reject discriminant-sizing attrs.) - - let v = present_first.unwrap(); - let kind = if def.is_enum() || variants[v].len() == 0 { - StructKind::AlwaysSized - } else { - let param_env = tcx.param_env(def.did); - let last_field = def.variants[v].fields.last().unwrap(); - let always_sized = - tcx.type_of(last_field.did).is_sized(tcx.at(DUMMY_SP), param_env); - if !always_sized { - StructKind::MaybeUnsized - } else { - StructKind::AlwaysSized - } - }; - - let mut st = self.univariant_uninterned(ty, &variants[v], &def.repr, kind)?; - st.variants = Variants::Single { index: v }; - let (start, end) = self.tcx.layout_scalar_valid_range(def.did); - match st.abi { - Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { - // the asserts ensure that we are not using the - // `#[rustc_layout_scalar_valid_range(n)]` - // attribute to widen the range of anything as that would probably - // result in UB somewhere - // FIXME(eddyb) the asserts are probably not needed, - // as larger validity ranges would result in missed - // optimizations, *not* wrongly assuming the inner - // value is valid. e.g. unions enlarge validity ranges, - // because the values may be uninitialized. - if let Bound::Included(start) = start { - // FIXME(eddyb) this might be incorrect - it doesn't - // account for wrap-around (end < start) ranges. - assert!(*scalar.valid_range.start() <= start); - scalar.valid_range = start..=*scalar.valid_range.end(); - } - if let Bound::Included(end) = end { - // FIXME(eddyb) this might be incorrect - it doesn't - // account for wrap-around (end < start) ranges. - assert!(*scalar.valid_range.end() >= end); - scalar.valid_range = *scalar.valid_range.start()..=end; - } - - // Update `largest_niche` if we have introduced a larger niche. - let niche = if def.repr.hide_niche() { - None - } else { - Niche::from_scalar(dl, Size::ZERO, scalar.clone()) - }; - if let Some(niche) = niche { - match &st.largest_niche { - Some(largest_niche) => { - // Replace the existing niche even if they're equal, - // because this one is at a lower offset. - if largest_niche.available(dl) <= niche.available(dl) { - st.largest_niche = Some(niche); - } - } - None => st.largest_niche = Some(niche), - } - } - } - _ => assert!( - start == Bound::Unbounded && end == Bound::Unbounded, - "nonscalar layout for layout_scalar_valid_range type {:?}: {:#?}", - def, - st, - ), - } - - return Ok(tcx.intern_layout(st)); - } - - // At this point, we have handled all unions and - // structs. (We have also handled univariant enums - // that allow representation optimization.) - assert!(def.is_enum()); - - // The current code for niche-filling relies on variant indices - // instead of actual discriminants, so dataful enums with - // explicit discriminants (RFC #2363) would misbehave. - let no_explicit_discriminants = def - .variants - .iter_enumerated() - .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32())); - - // Niche-filling enum optimization. - if !def.repr.inhibit_enum_layout_opt() && no_explicit_discriminants { - let mut dataful_variant = None; - let mut niche_variants = VariantIdx::MAX..=VariantIdx::new(0); - - // Find one non-ZST variant. - 'variants: for (v, fields) in variants.iter_enumerated() { - if absent(fields) { - continue 'variants; - } - for f in fields { - if !f.is_zst() { - if dataful_variant.is_none() { - dataful_variant = Some(v); - continue 'variants; - } else { - dataful_variant = None; - break 'variants; - } - } - } - niche_variants = *niche_variants.start().min(&v)..=v; - } - - if niche_variants.start() > niche_variants.end() { - dataful_variant = None; - } - - if let Some(i) = dataful_variant { - let count = (niche_variants.end().as_u32() - - niche_variants.start().as_u32() - + 1) as u128; - // FIXME(#62691) use the largest niche across all fields, - // not just the first one. - for (field_index, &field) in variants[i].iter().enumerate() { - let niche = match &field.largest_niche { - Some(niche) => niche, - _ => continue, - }; - let (niche_start, niche_scalar) = match niche.reserve(self, count) { - Some(pair) => pair, - None => continue, - }; - - let mut align = dl.aggregate_align; - let st = variants - .iter_enumerated() - .map(|(j, v)| { - let mut st = self.univariant_uninterned( - ty, - v, - &def.repr, - StructKind::AlwaysSized, - )?; - st.variants = Variants::Single { index: j }; - - align = align.max(st.align); - - Ok(st) - }) - .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; - - let offset = st[i].fields.offset(field_index) + niche.offset; - let size = st[i].size; - - let mut abi = match st[i].abi { - Abi::Scalar(_) => Abi::Scalar(niche_scalar.clone()), - Abi::ScalarPair(ref first, ref second) => { - // We need to use scalar_unit to reset the - // valid range to the maximal one for that - // primitive, because only the niche is - // guaranteed to be initialised, not the - // other primitive. - if offset.bytes() == 0 { - Abi::ScalarPair( - niche_scalar.clone(), - scalar_unit(second.value), - ) - } else { - Abi::ScalarPair( - scalar_unit(first.value), - niche_scalar.clone(), - ) - } - } - _ => Abi::Aggregate { sized: true }, - }; - - if st.iter().all(|v| v.abi.is_uninhabited()) { - abi = Abi::Uninhabited; - } - - let largest_niche = - Niche::from_scalar(dl, offset, niche_scalar.clone()); - - return Ok(tcx.intern_layout(LayoutDetails { - variants: Variants::Multiple { - discr: niche_scalar, - discr_kind: DiscriminantKind::Niche { - dataful_variant: i, - niche_variants, - niche_start, - }, - discr_index: 0, - variants: st, - }, - fields: FieldPlacement::Arbitrary { - offsets: vec![offset], - memory_index: vec![0], - }, - abi, - largest_niche, - size, - align, - })); - } - } - } - - let (mut min, mut max) = (i128::max_value(), i128::min_value()); - let discr_type = def.repr.discr_type(); - let bits = Integer::from_attr(self, discr_type).size().bits(); - for (i, discr) in def.discriminants(tcx) { - if variants[i].iter().any(|f| f.abi.is_uninhabited()) { - continue; - } - let mut x = discr.val as i128; - if discr_type.is_signed() { - // sign extend the raw representation to be an i128 - x = (x << (128 - bits)) >> (128 - bits); - } - if x < min { - min = x; - } - if x > max { - max = x; - } - } - // We might have no inhabited variants, so pretend there's at least one. - if (min, max) == (i128::max_value(), i128::min_value()) { - min = 0; - max = 0; - } - assert!(min <= max, "discriminant range is {}...{}", min, max); - let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max); - - let mut align = dl.aggregate_align; - let mut size = Size::ZERO; - - // We're interested in the smallest alignment, so start large. - let mut start_align = Align::from_bytes(256).unwrap(); - assert_eq!(Integer::for_align(dl, start_align), None); - - // repr(C) on an enum tells us to make a (tag, union) layout, - // so we need to grow the prefix alignment to be at least - // the alignment of the union. (This value is used both for - // determining the alignment of the overall enum, and the - // determining the alignment of the payload after the tag.) - let mut prefix_align = min_ity.align(dl).abi; - if def.repr.c() { - for fields in &variants { - for field in fields { - prefix_align = prefix_align.max(field.align.abi); - } - } - } - - // Create the set of structs that represent each variant. - let mut layout_variants = variants - .iter_enumerated() - .map(|(i, field_layouts)| { - let mut st = self.univariant_uninterned( - ty, - &field_layouts, - &def.repr, - StructKind::Prefixed(min_ity.size(), prefix_align), - )?; - st.variants = Variants::Single { index: i }; - // Find the first field we can't move later - // to make room for a larger discriminant. - for field in - st.fields.index_by_increasing_offset().map(|j| field_layouts[j]) - { - if !field.is_zst() || field.align.abi.bytes() != 1 { - start_align = start_align.min(field.align.abi); - break; - } - } - size = cmp::max(size, st.size); - align = align.max(st.align); - Ok(st) - }) - .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; - - // Align the maximum variant size to the largest alignment. - size = size.align_to(align.abi); - - if size.bytes() >= dl.obj_size_bound() { - return Err(LayoutError::SizeOverflow(ty)); - } - - let typeck_ity = Integer::from_attr(dl, def.repr.discr_type()); - if typeck_ity < min_ity { - // It is a bug if Layout decided on a greater discriminant size than typeck for - // some reason at this point (based on values discriminant can take on). Mostly - // because this discriminant will be loaded, and then stored into variable of - // type calculated by typeck. Consider such case (a bug): typeck decided on - // byte-sized discriminant, but layout thinks we need a 16-bit to store all - // discriminant values. That would be a bug, because then, in codegen, in order - // to store this 16-bit discriminant into 8-bit sized temporary some of the - // space necessary to represent would have to be discarded (or layout is wrong - // on thinking it needs 16 bits) - bug!( - "layout decided on a larger discriminant type ({:?}) than typeck ({:?})", - min_ity, - typeck_ity - ); - // However, it is fine to make discr type however large (as an optimisation) - // after this point – we’ll just truncate the value we load in codegen. - } - - // Check to see if we should use a different type for the - // discriminant. We can safely use a type with the same size - // as the alignment of the first field of each variant. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about its contents and - // won't be so conservative. - - // Use the initial field alignment - let mut ity = if def.repr.c() || def.repr.int.is_some() { - min_ity - } else { - Integer::for_align(dl, start_align).unwrap_or(min_ity) - }; - - // If the alignment is not larger than the chosen discriminant size, - // don't use the alignment as the final size. - if ity <= min_ity { - ity = min_ity; - } else { - // Patch up the variants' first few fields. - let old_ity_size = min_ity.size(); - let new_ity_size = ity.size(); - for variant in &mut layout_variants { - match variant.fields { - FieldPlacement::Arbitrary { ref mut offsets, .. } => { - for i in offsets { - if *i <= old_ity_size { - assert_eq!(*i, old_ity_size); - *i = new_ity_size; - } - } - // We might be making the struct larger. - if variant.size <= old_ity_size { - variant.size = new_ity_size; - } - } - _ => bug!(), - } - } - } - - let tag_mask = !0u128 >> (128 - ity.size().bits()); - let tag = Scalar { - value: Int(ity, signed), - valid_range: (min as u128 & tag_mask)..=(max as u128 & tag_mask), - }; - let mut abi = Abi::Aggregate { sized: true }; - if tag.value.size(dl) == size { - abi = Abi::Scalar(tag.clone()); - } else { - // Try to use a ScalarPair for all tagged enums. - let mut common_prim = None; - for (field_layouts, layout_variant) in variants.iter().zip(&layout_variants) { - let offsets = match layout_variant.fields { - FieldPlacement::Arbitrary { ref offsets, .. } => offsets, - _ => bug!(), - }; - let mut fields = - field_layouts.iter().zip(offsets).filter(|p| !p.0.is_zst()); - let (field, offset) = match (fields.next(), fields.next()) { - (None, None) => continue, - (Some(pair), None) => pair, - _ => { - common_prim = None; - break; - } - }; - let prim = match field.details.abi { - Abi::Scalar(ref scalar) => scalar.value, - _ => { - common_prim = None; - break; - } - }; - if let Some(pair) = common_prim { - // This is pretty conservative. We could go fancier - // by conflating things like i32 and u32, or even - // realising that (u8, u8) could just cohabit with - // u16 or even u32. - if pair != (prim, offset) { - common_prim = None; - break; - } - } else { - common_prim = Some((prim, offset)); - } - } - if let Some((prim, offset)) = common_prim { - let pair = self.scalar_pair(tag.clone(), scalar_unit(prim)); - let pair_offsets = match pair.fields { - FieldPlacement::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index, &[0, 1]); - offsets - } - _ => bug!(), - }; - if pair_offsets[0] == Size::ZERO - && pair_offsets[1] == *offset - && align == pair.align - && size == pair.size - { - // We can use `ScalarPair` only when it matches our - // already computed layout (including `#[repr(C)]`). - abi = pair.abi; - } - } - } - - if layout_variants.iter().all(|v| v.abi.is_uninhabited()) { - abi = Abi::Uninhabited; - } - - let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag.clone()); - - tcx.intern_layout(LayoutDetails { - variants: Variants::Multiple { - discr: tag, - discr_kind: DiscriminantKind::Tag, - discr_index: 0, - variants: layout_variants, - }, - fields: FieldPlacement::Arbitrary { - offsets: vec![Size::ZERO], - memory_index: vec![0], - }, - largest_niche, - abi, - align, - size, - }) - } - - // Types with no meaningful known layout. - ty::Projection(_) | ty::Opaque(..) => { - let normalized = tcx.normalize_erasing_regions(param_env, ty); - if ty == normalized { - return Err(LayoutError::Unknown(ty)); - } - tcx.layout_raw(param_env.and(normalized))? - } - - ty::Bound(..) - | ty::Placeholder(..) - | ty::UnnormalizedProjection(..) - | ty::GeneratorWitness(..) - | ty::Infer(_) => bug!("LayoutDetails::compute: unexpected type `{}`", ty), - - ty::Param(_) | ty::Error => { - return Err(LayoutError::Unknown(ty)); - } - }) - } -} - -/// Overlap eligibility and variant assignment for each GeneratorSavedLocal. -#[derive(Clone, Debug, PartialEq)] -enum SavedLocalEligibility { - Unassigned, - Assigned(VariantIdx), - // FIXME: Use newtype_index so we aren't wasting bytes - Ineligible(Option<u32>), -} - -// When laying out generators, we divide our saved local fields into two -// categories: overlap-eligible and overlap-ineligible. -// -// Those fields which are ineligible for overlap go in a "prefix" at the -// beginning of the layout, and always have space reserved for them. -// -// Overlap-eligible fields are only assigned to one variant, so we lay -// those fields out for each variant and put them right after the -// prefix. -// -// Finally, in the layout details, we point to the fields from the -// variants they are assigned to. It is possible for some fields to be -// included in multiple variants. No field ever "moves around" in the -// layout; its offset is always the same. -// -// Also included in the layout are the upvars and the discriminant. -// These are included as fields on the "outer" layout; they are not part -// of any variant. -impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { - /// Compute the eligibility and assignment of each local. - fn generator_saved_local_eligibility( - &self, - info: &GeneratorLayout<'tcx>, - ) -> (BitSet<GeneratorSavedLocal>, IndexVec<GeneratorSavedLocal, SavedLocalEligibility>) { - use SavedLocalEligibility::*; - - let mut assignments: IndexVec<GeneratorSavedLocal, SavedLocalEligibility> = - IndexVec::from_elem_n(Unassigned, info.field_tys.len()); - - // The saved locals not eligible for overlap. These will get - // "promoted" to the prefix of our generator. - let mut ineligible_locals = BitSet::new_empty(info.field_tys.len()); - - // Figure out which of our saved locals are fields in only - // one variant. The rest are deemed ineligible for overlap. - for (variant_index, fields) in info.variant_fields.iter_enumerated() { - for local in fields { - match assignments[*local] { - Unassigned => { - assignments[*local] = Assigned(variant_index); - } - Assigned(idx) => { - // We've already seen this local at another suspension - // point, so it is no longer a candidate. - trace!( - "removing local {:?} in >1 variant ({:?}, {:?})", - local, - variant_index, - idx - ); - ineligible_locals.insert(*local); - assignments[*local] = Ineligible(None); - } - Ineligible(_) => {} - } - } - } - - // Next, check every pair of eligible locals to see if they - // conflict. - for local_a in info.storage_conflicts.rows() { - let conflicts_a = info.storage_conflicts.count(local_a); - if ineligible_locals.contains(local_a) { - continue; - } - - for local_b in info.storage_conflicts.iter(local_a) { - // local_a and local_b are storage live at the same time, therefore they - // cannot overlap in the generator layout. The only way to guarantee - // this is if they are in the same variant, or one is ineligible - // (which means it is stored in every variant). - if ineligible_locals.contains(local_b) - || assignments[local_a] == assignments[local_b] - { - continue; - } - - // If they conflict, we will choose one to make ineligible. - // This is not always optimal; it's just a greedy heuristic that - // seems to produce good results most of the time. - let conflicts_b = info.storage_conflicts.count(local_b); - let (remove, other) = - if conflicts_a > conflicts_b { (local_a, local_b) } else { (local_b, local_a) }; - ineligible_locals.insert(remove); - assignments[remove] = Ineligible(None); - trace!("removing local {:?} due to conflict with {:?}", remove, other); - } - } - - // Count the number of variants in use. If only one of them, then it is - // impossible to overlap any locals in our layout. In this case it's - // always better to make the remaining locals ineligible, so we can - // lay them out with the other locals in the prefix and eliminate - // unnecessary padding bytes. - { - let mut used_variants = BitSet::new_empty(info.variant_fields.len()); - for assignment in &assignments { - match assignment { - Assigned(idx) => { - used_variants.insert(*idx); - } - _ => {} - } - } - if used_variants.count() < 2 { - for assignment in assignments.iter_mut() { - *assignment = Ineligible(None); - } - ineligible_locals.insert_all(); - } - } - - // Write down the order of our locals that will be promoted to the prefix. - { - let mut idx = 0u32; - for local in ineligible_locals.iter() { - assignments[local] = Ineligible(Some(idx)); - idx += 1; - } - } - debug!("generator saved local assignments: {:?}", assignments); - - (ineligible_locals, assignments) - } - - /// Compute the full generator layout. - fn generator_layout( - &self, - ty: Ty<'tcx>, - def_id: hir::def_id::DefId, - substs: SubstsRef<'tcx>, - ) -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> { - use SavedLocalEligibility::*; - let tcx = self.tcx; - - let subst_field = |ty: Ty<'tcx>| ty.subst(tcx, substs); - - let info = tcx.generator_layout(def_id); - let (ineligible_locals, assignments) = self.generator_saved_local_eligibility(&info); - - // Build a prefix layout, including "promoting" all ineligible - // locals as part of the prefix. We compute the layout of all of - // these fields at once to get optimal packing. - let discr_index = substs.as_generator().prefix_tys(def_id, tcx).count(); - // FIXME(eddyb) set the correct vaidity range for the discriminant. - let discr_layout = self.layout_of(substs.as_generator().discr_ty(tcx))?; - let discr = match &discr_layout.abi { - Abi::Scalar(s) => s.clone(), - _ => bug!(), - }; - let promoted_layouts = ineligible_locals - .iter() - .map(|local| subst_field(info.field_tys[local])) - .map(|ty| tcx.mk_maybe_uninit(ty)) - .map(|ty| self.layout_of(ty)); - let prefix_layouts = substs - .as_generator() - .prefix_tys(def_id, tcx) - .map(|ty| self.layout_of(ty)) - .chain(iter::once(Ok(discr_layout))) - .chain(promoted_layouts) - .collect::<Result<Vec<_>, _>>()?; - let prefix = self.univariant_uninterned( - ty, - &prefix_layouts, - &ReprOptions::default(), - StructKind::AlwaysSized, - )?; - - let (prefix_size, prefix_align) = (prefix.size, prefix.align); - - // Split the prefix layout into the "outer" fields (upvars and - // discriminant) and the "promoted" fields. Promoted fields will - // get included in each variant that requested them in - // GeneratorLayout. - debug!("prefix = {:#?}", prefix); - let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields { - FieldPlacement::Arbitrary { mut offsets, memory_index } => { - let mut inverse_memory_index = invert_mapping(&memory_index); - - // "a" (`0..b_start`) and "b" (`b_start..`) correspond to - // "outer" and "promoted" fields respectively. - let b_start = (discr_index + 1) as u32; - let offsets_b = offsets.split_off(b_start as usize); - let offsets_a = offsets; - - // Disentangle the "a" and "b" components of `inverse_memory_index` - // by preserving the order but keeping only one disjoint "half" each. - // FIXME(eddyb) build a better abstraction for permutations, if possible. - let inverse_memory_index_b: Vec<_> = - inverse_memory_index.iter().filter_map(|&i| i.checked_sub(b_start)).collect(); - inverse_memory_index.retain(|&i| i < b_start); - let inverse_memory_index_a = inverse_memory_index; - - // Since `inverse_memory_index_{a,b}` each only refer to their - // respective fields, they can be safely inverted - let memory_index_a = invert_mapping(&inverse_memory_index_a); - let memory_index_b = invert_mapping(&inverse_memory_index_b); - - let outer_fields = - FieldPlacement::Arbitrary { offsets: offsets_a, memory_index: memory_index_a }; - (outer_fields, offsets_b, memory_index_b) - } - _ => bug!(), - }; - - let mut size = prefix.size; - let mut align = prefix.align; - let variants = info - .variant_fields - .iter_enumerated() - .map(|(index, variant_fields)| { - // Only include overlap-eligible fields when we compute our variant layout. - let variant_only_tys = variant_fields - .iter() - .filter(|local| match assignments[**local] { - Unassigned => bug!(), - Assigned(v) if v == index => true, - Assigned(_) => bug!("assignment does not match variant"), - Ineligible(_) => false, - }) - .map(|local| subst_field(info.field_tys[*local])); - - let mut variant = self.univariant_uninterned( - ty, - &variant_only_tys - .map(|ty| self.layout_of(ty)) - .collect::<Result<Vec<_>, _>>()?, - &ReprOptions::default(), - StructKind::Prefixed(prefix_size, prefix_align.abi), - )?; - variant.variants = Variants::Single { index }; - - let (offsets, memory_index) = match variant.fields { - FieldPlacement::Arbitrary { offsets, memory_index } => (offsets, memory_index), - _ => bug!(), - }; - - // Now, stitch the promoted and variant-only fields back together in - // the order they are mentioned by our GeneratorLayout. - // Because we only use some subset (that can differ between variants) - // of the promoted fields, we can't just pick those elements of the - // `promoted_memory_index` (as we'd end up with gaps). - // So instead, we build an "inverse memory_index", as if all of the - // promoted fields were being used, but leave the elements not in the - // subset as `INVALID_FIELD_IDX`, which we can filter out later to - // obtain a valid (bijective) mapping. - const INVALID_FIELD_IDX: u32 = !0; - let mut combined_inverse_memory_index = - vec![INVALID_FIELD_IDX; promoted_memory_index.len() + memory_index.len()]; - let mut offsets_and_memory_index = offsets.into_iter().zip(memory_index); - let combined_offsets = variant_fields - .iter() - .enumerate() - .map(|(i, local)| { - let (offset, memory_index) = match assignments[*local] { - Unassigned => bug!(), - Assigned(_) => { - let (offset, memory_index) = - offsets_and_memory_index.next().unwrap(); - (offset, promoted_memory_index.len() as u32 + memory_index) - } - Ineligible(field_idx) => { - let field_idx = field_idx.unwrap() as usize; - (promoted_offsets[field_idx], promoted_memory_index[field_idx]) - } - }; - combined_inverse_memory_index[memory_index as usize] = i as u32; - offset - }) - .collect(); - - // Remove the unused slots and invert the mapping to obtain the - // combined `memory_index` (also see previous comment). - combined_inverse_memory_index.retain(|&i| i != INVALID_FIELD_IDX); - let combined_memory_index = invert_mapping(&combined_inverse_memory_index); - - variant.fields = FieldPlacement::Arbitrary { - offsets: combined_offsets, - memory_index: combined_memory_index, - }; - - size = size.max(variant.size); - align = align.max(variant.align); - Ok(variant) - }) - .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; - - size = size.align_to(align.abi); - - let abi = if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi.is_uninhabited()) - { - Abi::Uninhabited - } else { - Abi::Aggregate { sized: true } - }; - - let layout = tcx.intern_layout(LayoutDetails { - variants: Variants::Multiple { - discr, - discr_kind: DiscriminantKind::Tag, - discr_index, - variants, - }, - fields: outer_fields, - abi, - largest_niche: prefix.largest_niche, - size, - align, - }); - debug!("generator layout ({:?}): {:#?}", ty, layout); - Ok(layout) - } - - /// This is invoked by the `layout_raw` query to record the final - /// layout of each type. - #[inline(always)] - fn record_layout_for_printing(&self, layout: TyLayout<'tcx>) { - // If we are running with `-Zprint-type-sizes`, maybe record layouts - // for dumping later. - if self.tcx.sess.opts.debugging_opts.print_type_sizes { - self.record_layout_for_printing_outlined(layout) - } - } - - fn record_layout_for_printing_outlined(&self, layout: TyLayout<'tcx>) { - // Ignore layouts that are done with non-empty environments or - // non-monomorphic layouts, as the user only wants to see the stuff - // resulting from the final codegen session. - if layout.ty.has_param_types() || !self.param_env.caller_bounds.is_empty() { - return; - } - - // (delay format until we actually need it) - let record = |kind, packed, opt_discr_size, variants| { - let type_desc = format!("{:?}", layout.ty); - self.tcx.sess.code_stats.record_type_size( - kind, - type_desc, - layout.align.abi, - layout.size, - packed, - opt_discr_size, - variants, - ); - }; - - let adt_def = match layout.ty.kind { - ty::Adt(ref adt_def, _) => { - debug!("print-type-size t: `{:?}` process adt", layout.ty); - adt_def - } - - ty::Closure(..) => { - debug!("print-type-size t: `{:?}` record closure", layout.ty); - record(DataTypeKind::Closure, false, None, vec![]); - return; - } - - _ => { - debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty); - return; - } - }; - - let adt_kind = adt_def.adt_kind(); - let adt_packed = adt_def.repr.pack.is_some(); - - let build_variant_info = |n: Option<Ident>, flds: &[ast::Name], layout: TyLayout<'tcx>| { - let mut min_size = Size::ZERO; - let field_info: Vec<_> = flds - .iter() - .enumerate() - .map(|(i, &name)| match layout.field(self, i) { - Err(err) => { - bug!("no layout found for field {}: `{:?}`", name, err); - } - Ok(field_layout) => { - let offset = layout.fields.offset(i); - let field_end = offset + field_layout.size; - if min_size < field_end { - min_size = field_end; - } - session::FieldInfo { - name: name.to_string(), - offset: offset.bytes(), - size: field_layout.size.bytes(), - align: field_layout.align.abi.bytes(), - } - } - }) - .collect(); - - session::VariantInfo { - name: n.map(|n| n.to_string()), - kind: if layout.is_unsized() { - session::SizeKind::Min - } else { - session::SizeKind::Exact - }, - align: layout.align.abi.bytes(), - size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() }, - fields: field_info, - } - }; - - match layout.variants { - Variants::Single { index } => { - debug!("print-type-size `{:#?}` variant {}", layout, adt_def.variants[index].ident); - if !adt_def.variants.is_empty() { - let variant_def = &adt_def.variants[index]; - let fields: Vec<_> = variant_def.fields.iter().map(|f| f.ident.name).collect(); - record( - adt_kind.into(), - adt_packed, - None, - vec![build_variant_info(Some(variant_def.ident), &fields, layout)], - ); - } else { - // (This case arises for *empty* enums; so give it - // zero variants.) - record(adt_kind.into(), adt_packed, None, vec![]); - } - } - - Variants::Multiple { ref discr, ref discr_kind, .. } => { - debug!( - "print-type-size `{:#?}` adt general variants def {}", - layout.ty, - adt_def.variants.len() - ); - let variant_infos: Vec<_> = adt_def - .variants - .iter_enumerated() - .map(|(i, variant_def)| { - let fields: Vec<_> = - variant_def.fields.iter().map(|f| f.ident.name).collect(); - build_variant_info( - Some(variant_def.ident), - &fields, - layout.for_variant(self, i), - ) - }) - .collect(); - record( - adt_kind.into(), - adt_packed, - match discr_kind { - DiscriminantKind::Tag => Some(discr.value.size(self)), - _ => None, - }, - variant_infos, - ); - } - } - } -} - -/// Type size "skeleton", i.e., the only information determining a type's size. -/// While this is conservative, (aside from constant sizes, only pointers, -/// newtypes thereof and null pointer optimized enums are allowed), it is -/// enough to statically check common use cases of transmute. -#[derive(Copy, Clone, Debug)] -pub enum SizeSkeleton<'tcx> { - /// Any statically computable Layout. - Known(Size), - - /// A potentially-fat pointer. - Pointer { - /// If true, this pointer is never null. - non_zero: bool, - /// The type which determines the unsized metadata, if any, - /// of this pointer. Either a type parameter or a projection - /// depending on one, with regions erased. - tail: Ty<'tcx>, - }, -} - -impl<'tcx> SizeSkeleton<'tcx> { - pub fn compute( - ty: Ty<'tcx>, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> { - debug_assert!(!ty.has_infer_types()); - - // First try computing a static layout. - let err = match tcx.layout_of(param_env.and(ty)) { - Ok(layout) => { - return Ok(SizeSkeleton::Known(layout.size)); - } - Err(err) => err, - }; - - match ty.kind { - ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - let non_zero = !ty.is_unsafe_ptr(); - let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env); - match tail.kind { - ty::Param(_) | ty::Projection(_) => { - debug_assert!(tail.has_param_types()); - Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(&tail) }) - } - _ => bug!( - "SizeSkeleton::compute({}): layout errored ({}), yet \ - tail `{}` is not a type parameter or a projection", - ty, - err, - tail - ), - } - } - - ty::Adt(def, substs) => { - // Only newtypes and enums w/ nullable pointer optimization. - if def.is_union() || def.variants.is_empty() || def.variants.len() > 2 { - return Err(err); - } - - // Get a zero-sized variant or a pointer newtype. - let zero_or_ptr_variant = |i| { - let i = VariantIdx::new(i); - let fields = def.variants[i] - .fields - .iter() - .map(|field| SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env)); - let mut ptr = None; - for field in fields { - let field = field?; - match field { - SizeSkeleton::Known(size) => { - if size.bytes() > 0 { - return Err(err); - } - } - SizeSkeleton::Pointer { .. } => { - if ptr.is_some() { - return Err(err); - } - ptr = Some(field); - } - } - } - Ok(ptr) - }; - - let v0 = zero_or_ptr_variant(0)?; - // Newtype. - if def.variants.len() == 1 { - if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 { - return Ok(SizeSkeleton::Pointer { - non_zero: non_zero - || match tcx.layout_scalar_valid_range(def.did) { - (Bound::Included(start), Bound::Unbounded) => start > 0, - (Bound::Included(start), Bound::Included(end)) => { - 0 < start && start < end - } - _ => false, - }, - tail, - }); - } else { - return Err(err); - } - } - - let v1 = zero_or_ptr_variant(1)?; - // Nullable pointer enum optimization. - match (v0, v1) { - (Some(SizeSkeleton::Pointer { non_zero: true, tail }), None) - | (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => { - Ok(SizeSkeleton::Pointer { non_zero: false, tail }) - } - _ => Err(err), - } - } - - ty::Projection(_) | ty::Opaque(..) => { - let normalized = tcx.normalize_erasing_regions(param_env, ty); - if ty == normalized { - Err(err) - } else { - SizeSkeleton::compute(normalized, tcx, param_env) - } - } - - _ => Err(err), - } - } - - pub fn same_size(self, other: SizeSkeleton<'_>) -> bool { - match (self, other) { - (SizeSkeleton::Known(a), SizeSkeleton::Known(b)) => a == b, - (SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => { - a == b - } - _ => false, - } - } -} - -pub trait HasTyCtxt<'tcx>: HasDataLayout { - fn tcx(&self) -> TyCtxt<'tcx>; -} - -pub trait HasParamEnv<'tcx> { - fn param_env(&self) -> ty::ParamEnv<'tcx>; -} - -impl<'tcx> HasDataLayout for TyCtxt<'tcx> { - fn data_layout(&self) -> &TargetDataLayout { - &self.data_layout - } -} - -impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - *self - } -} - -impl<'tcx, C> HasParamEnv<'tcx> for LayoutCx<'tcx, C> { - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } -} - -impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> { - fn data_layout(&self) -> &TargetDataLayout { - self.tcx.data_layout() - } -} - -impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx.tcx() - } -} - -pub trait MaybeResult<T> { - type Error; - - fn from(x: Result<T, Self::Error>) -> Self; - fn to_result(self) -> Result<T, Self::Error>; -} - -impl<T> MaybeResult<T> for T { - type Error = !; - - fn from(x: Result<T, Self::Error>) -> Self { - let Ok(x) = x; - x - } - fn to_result(self) -> Result<T, Self::Error> { - Ok(self) - } -} - -impl<T, E> MaybeResult<T> for Result<T, E> { - type Error = E; - - fn from(x: Result<T, Self::Error>) -> Self { - x - } - fn to_result(self) -> Result<T, Self::Error> { - self - } -} - -pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>; - -impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> { - type Ty = Ty<'tcx>; - type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>; - - /// Computes the layout of a type. Note that this implicitly - /// executes in "reveal all" mode. - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout { - let param_env = self.param_env.with_reveal_all(); - let ty = self.tcx.normalize_erasing_regions(param_env, ty); - let details = self.tcx.layout_raw(param_env.and(ty))?; - let layout = TyLayout { ty, details }; - - // N.B., this recording is normally disabled; when enabled, it - // can however trigger recursive invocations of `layout_of`. - // Therefore, we execute it *after* the main query has - // completed, to avoid problems around recursive structures - // and the like. (Admittedly, I wasn't able to reproduce a problem - // here, but it seems like the right thing to do. -nmatsakis) - self.record_layout_for_printing(layout); - - Ok(layout) - } -} - -impl LayoutOf for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> { - type Ty = Ty<'tcx>; - type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>; - - /// Computes the layout of a type. Note that this implicitly - /// executes in "reveal all" mode. - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout { - let param_env = self.param_env.with_reveal_all(); - let ty = self.tcx.normalize_erasing_regions(param_env, ty); - let details = self.tcx.layout_raw(param_env.and(ty))?; - let layout = TyLayout { ty, details }; - - // N.B., this recording is normally disabled; when enabled, it - // can however trigger recursive invocations of `layout_of`. - // Therefore, we execute it *after* the main query has - // completed, to avoid problems around recursive structures - // and the like. (Admittedly, I wasn't able to reproduce a problem - // here, but it seems like the right thing to do. -nmatsakis) - let cx = LayoutCx { tcx: *self.tcx, param_env: self.param_env }; - cx.record_layout_for_printing(layout); - - Ok(layout) - } -} - -// Helper (inherent) `layout_of` methods to avoid pushing `LayoutCx` to users. -impl TyCtxt<'tcx> { - /// Computes the layout of a type. Note that this implicitly - /// executes in "reveal all" mode. - #[inline] - pub fn layout_of( - self, - param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, - ) -> Result<TyLayout<'tcx>, LayoutError<'tcx>> { - let cx = LayoutCx { tcx: self, param_env: param_env_and_ty.param_env }; - cx.layout_of(param_env_and_ty.value) - } -} - -impl ty::query::TyCtxtAt<'tcx> { - /// Computes the layout of a type. Note that this implicitly - /// executes in "reveal all" mode. - #[inline] - pub fn layout_of( - self, - param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, - ) -> Result<TyLayout<'tcx>, LayoutError<'tcx>> { - let cx = LayoutCx { tcx: self.at(self.span), param_env: param_env_and_ty.param_env }; - cx.layout_of(param_env_and_ty.value) - } -} - -impl<'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> -where - C: LayoutOf<Ty = Ty<'tcx>, TyLayout: MaybeResult<TyLayout<'tcx>>> - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>, -{ - fn for_variant(this: TyLayout<'tcx>, cx: &C, variant_index: VariantIdx) -> TyLayout<'tcx> { - let details = match this.variants { - Variants::Single { index } if index == variant_index => this.details, - - Variants::Single { index } => { - // Deny calling for_variant more than once for non-Single enums. - if let Ok(layout) = cx.layout_of(this.ty).to_result() { - assert_eq!(layout.variants, Variants::Single { index }); - } - - let fields = match this.ty.kind { - ty::Adt(def, _) => def.variants[variant_index].fields.len(), - _ => bug!(), - }; - let tcx = cx.tcx(); - tcx.intern_layout(LayoutDetails { - variants: Variants::Single { index: variant_index }, - fields: FieldPlacement::Union(fields), - abi: Abi::Uninhabited, - largest_niche: None, - align: tcx.data_layout.i8_align, - size: Size::ZERO, - }) - } - - Variants::Multiple { ref variants, .. } => &variants[variant_index], - }; - - assert_eq!(details.variants, Variants::Single { index: variant_index }); - - TyLayout { ty: this.ty, details } - } - - fn field(this: TyLayout<'tcx>, cx: &C, i: usize) -> C::TyLayout { - let tcx = cx.tcx(); - let discr_layout = |discr: &Scalar| -> C::TyLayout { - let layout = LayoutDetails::scalar(cx, discr.clone()); - MaybeResult::from(Ok(TyLayout { - details: tcx.intern_layout(layout), - ty: discr.value.to_ty(tcx), - })) - }; - - cx.layout_of(match this.ty.kind { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::FnPtr(_) - | ty::Never - | ty::FnDef(..) - | ty::GeneratorWitness(..) - | ty::Foreign(..) - | ty::Dynamic(..) => bug!("TyLayout::field_type({:?}): not applicable", this), - - // Potentially-fat pointers. - ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - assert!(i < this.fields.count()); - - // Reuse the fat `*T` type as its own thin pointer data field. - // This provides information about, e.g., DST struct pointees - // (which may have no non-DST form), and will work as long - // as the `Abi` or `FieldPlacement` is checked by users. - if i == 0 { - let nil = tcx.mk_unit(); - let ptr_ty = if this.ty.is_unsafe_ptr() { - tcx.mk_mut_ptr(nil) - } else { - tcx.mk_mut_ref(tcx.lifetimes.re_static, nil) - }; - return MaybeResult::from(cx.layout_of(ptr_ty).to_result().map( - |mut ptr_layout| { - ptr_layout.ty = this.ty; - ptr_layout - }, - )); - } - - match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind { - ty::Slice(_) | ty::Str => tcx.types.usize, - ty::Dynamic(_, _) => { - tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3)) - /* FIXME: use actual fn pointers - Warning: naively computing the number of entries in the - vtable by counting the methods on the trait + methods on - all parent traits does not work, because some methods can - be not object safe and thus excluded from the vtable. - Increase this counter if you tried to implement this but - failed to do it without duplicating a lot of code from - other places in the compiler: 2 - tcx.mk_tup(&[ - tcx.mk_array(tcx.types.usize, 3), - tcx.mk_array(Option<fn()>), - ]) - */ - } - _ => bug!("TyLayout::field_type({:?}): not applicable", this), - } - } - - // Arrays and slices. - ty::Array(element, _) | ty::Slice(element) => element, - ty::Str => tcx.types.u8, - - // Tuples, generators and closures. - ty::Closure(def_id, ref substs) => { - substs.as_closure().upvar_tys(def_id, tcx).nth(i).unwrap() - } - - ty::Generator(def_id, ref substs, _) => match this.variants { - Variants::Single { index } => substs - .as_generator() - .state_tys(def_id, tcx) - .nth(index.as_usize()) - .unwrap() - .nth(i) - .unwrap(), - Variants::Multiple { ref discr, discr_index, .. } => { - if i == discr_index { - return discr_layout(discr); - } - substs.as_generator().prefix_tys(def_id, tcx).nth(i).unwrap() - } - }, - - ty::Tuple(tys) => tys[i].expect_ty(), - - // SIMD vector types. - ty::Adt(def, ..) if def.repr.simd() => this.ty.simd_type(tcx), - - // ADTs. - ty::Adt(def, substs) => { - match this.variants { - Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs), - - // Discriminant field for enums (where applicable). - Variants::Multiple { ref discr, .. } => { - assert_eq!(i, 0); - return discr_layout(discr); - } - } - } - - ty::Projection(_) - | ty::UnnormalizedProjection(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Opaque(..) - | ty::Param(_) - | ty::Infer(_) - | ty::Error => bug!("TyLayout::field_type: unexpected type `{}`", this.ty), - }) - } - - fn pointee_info_at(this: TyLayout<'tcx>, cx: &C, offset: Size) -> Option<PointeeInfo> { - match this.ty.kind { - ty::RawPtr(mt) if offset.bytes() == 0 => { - cx.layout_of(mt.ty).to_result().ok().map(|layout| PointeeInfo { - size: layout.size, - align: layout.align.abi, - safe: None, - }) - } - - ty::Ref(_, ty, mt) if offset.bytes() == 0 => { - let tcx = cx.tcx(); - let is_freeze = ty.is_freeze(tcx, cx.param_env(), DUMMY_SP); - let kind = match mt { - hir::Mutability::Not => { - if is_freeze { - PointerKind::Frozen - } else { - PointerKind::Shared - } - } - hir::Mutability::Mut => { - // Previously we would only emit noalias annotations for LLVM >= 6 or in - // panic=abort mode. That was deemed right, as prior versions had many bugs - // in conjunction with unwinding, but later versions didn’t seem to have - // said issues. See issue #31681. - // - // Alas, later on we encountered a case where noalias would generate wrong - // code altogether even with recent versions of LLVM in *safe* code with no - // unwinding involved. See #54462. - // - // For now, do not enable mutable_noalias by default at all, while the - // issue is being figured out. - let mutable_noalias = - tcx.sess.opts.debugging_opts.mutable_noalias.unwrap_or(false); - if mutable_noalias { - PointerKind::UniqueBorrowed - } else { - PointerKind::Shared - } - } - }; - - cx.layout_of(ty).to_result().ok().map(|layout| PointeeInfo { - size: layout.size, - align: layout.align.abi, - safe: Some(kind), - }) - } - - _ => { - let mut data_variant = match this.variants { - // Within the discriminant field, only the niche itself is - // always initialized, so we only check for a pointer at its - // offset. - // - // If the niche is a pointer, it's either valid (according - // to its type), or null (which the niche field's scalar - // validity range encodes). This allows using - // `dereferenceable_or_null` for e.g., `Option<&T>`, and - // this will continue to work as long as we don't start - // using more niches than just null (e.g., the first page of - // the address space, or unaligned pointers). - Variants::Multiple { - discr_kind: DiscriminantKind::Niche { dataful_variant, .. }, - discr_index, - .. - } if this.fields.offset(discr_index) == offset => { - Some(this.for_variant(cx, dataful_variant)) - } - _ => Some(this), - }; - - if let Some(variant) = data_variant { - // We're not interested in any unions. - if let FieldPlacement::Union(_) = variant.fields { - data_variant = None; - } - } - - let mut result = None; - - if let Some(variant) = data_variant { - let ptr_end = offset + Pointer.size(cx); - for i in 0..variant.fields.count() { - let field_start = variant.fields.offset(i); - if field_start <= offset { - let field = variant.field(cx, i); - result = field.to_result().ok().and_then(|field| { - if ptr_end <= field_start + field.size { - // We found the right field, look inside it. - field.pointee_info_at(cx, offset - field_start) - } else { - None - } - }); - if result.is_some() { - break; - } - } - } - } - - // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`. - if let Some(ref mut pointee) = result { - if let ty::Adt(def, _) = this.ty.kind { - if def.is_box() && offset.bytes() == 0 { - pointee.safe = Some(PointerKind::UniqueOwned); - } - } - } - - result - } - } - } -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for LayoutError<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use crate::ty::layout::LayoutError::*; - mem::discriminant(self).hash_stable(hcx, hasher); - - match *self { - Unknown(t) | SizeOverflow(t) => t.hash_stable(hcx, hasher), - } - } -} - -impl<'tcx> ty::Instance<'tcx> { - // NOTE(eddyb) this is private to avoid using it from outside of - // `FnAbi::of_instance` - any other uses are either too high-level - // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead), - // or should go through `FnAbi` instead, to avoid losing any - // adjustments `FnAbi::of_instance` might be performing. - fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { - let ty = self.monomorphic_ty(tcx); - match ty.kind { - ty::FnDef(..) | - // Shims currently have type FnPtr. Not sure this should remain. - ty::FnPtr(_) => { - let mut sig = ty.fn_sig(tcx); - if let ty::InstanceDef::VtableShim(..) = self.def { - // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. - sig = sig.map_bound(|mut sig| { - let mut inputs_and_output = sig.inputs_and_output.to_vec(); - inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]); - sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output); - sig - }); - } - sig - } - ty::Closure(def_id, substs) => { - let sig = substs.as_closure().sig(def_id, tcx); - - let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); - sig.map_bound(|sig| tcx.mk_fn_sig( - iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), - sig.output(), - sig.c_variadic, - sig.unsafety, - sig.abi - )) - } - ty::Generator(def_id, substs, _) => { - let sig = substs.as_generator().poly_sig(def_id, tcx); - - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); - let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); - - let pin_did = tcx.lang_items().pin_type().unwrap(); - let pin_adt_ref = tcx.adt_def(pin_did); - let pin_substs = tcx.intern_substs(&[env_ty.into()]); - let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs); - - sig.map_bound(|sig| { - let state_did = tcx.lang_items().gen_state().unwrap(); - let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.intern_substs(&[ - sig.yield_ty.into(), - sig.return_ty.into(), - ]); - let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); - - tcx.mk_fn_sig( - [env_ty, sig.resume_ty].iter(), - &ret_ty, - false, - hir::Unsafety::Normal, - rustc_target::spec::abi::Abi::Rust - ) - }) - } - _ => bug!("unexpected type {:?} in Instance::fn_sig", ty) - } - } -} - -pub trait FnAbiExt<'tcx, C> -where - C: LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>, -{ - /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. - /// - /// NB: this doesn't handle virtual calls - those should use `FnAbi::of_instance` - /// instead, where the instance is a `InstanceDef::Virtual`. - fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; - - /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for - /// direct calls to an `fn`. - /// - /// NB: that includes virtual calls, which are represented by "direct calls" - /// to a `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`). - fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; - - fn new_internal( - cx: &C, - sig: ty::PolyFnSig<'tcx>, - extra_args: &[Ty<'tcx>], - caller_location: Option<Ty<'tcx>>, - mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>, - ) -> Self; - fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi); -} - -impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>> -where - C: LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>, -{ - fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { - call::FnAbi::new_internal(cx, sig, extra_args, None, |ty, _| ArgAbi::new(cx.layout_of(ty))) - } - - fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { - let sig = instance.fn_sig_for_fn_abi(cx.tcx()); - - let caller_location = if instance.def.requires_caller_location(cx.tcx()) { - Some(cx.tcx().caller_location_ty()) - } else { - None - }; - - call::FnAbi::new_internal(cx, sig, extra_args, caller_location, |ty, arg_idx| { - let mut layout = cx.layout_of(ty); - // Don't pass the vtable, it's not an argument of the virtual fn. - // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` - // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen - if let (ty::InstanceDef::Virtual(..), Some(0)) = (&instance.def, arg_idx) { - let fat_pointer_ty = if layout.is_unsized() { - // unsized `self` is passed as a pointer to `self` - // FIXME (mikeyhew) change this to use &own if it is ever added to the language - cx.tcx().mk_mut_ptr(layout.ty) - } else { - match layout.abi { - Abi::ScalarPair(..) => (), - _ => bug!("receiver type has unsupported layout: {:?}", layout), - } - - // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self> - // with a Scalar (not ScalarPair) ABI. This is a hack that is understood - // elsewhere in the compiler as a method on a `dyn Trait`. - // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we - // get a built-in pointer type - let mut fat_pointer_layout = layout; - 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() - && !fat_pointer_layout.ty.is_region_ptr() - { - for i in 0..fat_pointer_layout.fields.count() { - let field_layout = fat_pointer_layout.field(cx, i); - - if !field_layout.is_zst() { - fat_pointer_layout = field_layout; - continue 'descend_newtypes; - } - } - - bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout); - } - - fat_pointer_layout.ty - }; - - // we now have a type like `*mut RcBox<dyn Trait>` - // change its layout to that of `*mut ()`, a thin pointer, but keep the same type - // this is understood as a special case elsewhere in the compiler - let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit()); - layout = cx.layout_of(unit_pointer_ty); - layout.ty = fat_pointer_ty; - } - ArgAbi::new(layout) - }) - } - - fn new_internal( - cx: &C, - sig: ty::PolyFnSig<'tcx>, - extra_args: &[Ty<'tcx>], - caller_location: Option<Ty<'tcx>>, - mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>, - ) -> Self { - debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args); - - let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - - use rustc_target::spec::abi::Abi::*; - let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) { - RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, - - // It's the ABI's job to select this, not ours. - System => bug!("system abi should be selected elsewhere"), - EfiApi => bug!("eficall abi should be selected elsewhere"), - - Stdcall => Conv::X86Stdcall, - Fastcall => Conv::X86Fastcall, - Vectorcall => Conv::X86VectorCall, - Thiscall => Conv::X86ThisCall, - C => Conv::C, - Unadjusted => Conv::C, - Win64 => Conv::X86_64Win64, - SysV64 => Conv::X86_64SysV, - Aapcs => Conv::ArmAapcs, - PtxKernel => Conv::PtxKernel, - Msp430Interrupt => Conv::Msp430Intr, - X86Interrupt => Conv::X86Intr, - AmdGpuKernel => Conv::AmdGpuKernel, - - // These API constants ought to be more specific... - Cdecl => Conv::C, - }; - - let mut inputs = sig.inputs(); - let extra_args = if sig.abi == RustCall { - assert!(!sig.c_variadic && extra_args.is_empty()); - - if let Some(input) = sig.inputs().last() { - if let ty::Tuple(tupled_arguments) = input.kind { - inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - tupled_arguments.iter().map(|k| k.expect_ty()).collect() - } else { - bug!( - "argument to function with \"rust-call\" ABI \ - is not a tuple" - ); - } - } else { - bug!( - "argument to function with \"rust-call\" ABI \ - is not a tuple" - ); - } - } else { - assert!(sig.c_variadic || extra_args.is_empty()); - extra_args.to_vec() - }; - - let target = &cx.tcx().sess.target.target; - let win_x64_gnu = - target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu"; - let linux_s390x = - target.target_os == "linux" && target.arch == "s390x" && target.target_env == "gnu"; - let linux_sparc64 = - target.target_os == "linux" && target.arch == "sparc64" && target.target_env == "gnu"; - let rust_abi = match sig.abi { - RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, - _ => false, - }; - - // Handle safe Rust thin and fat pointers. - let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, - scalar: &Scalar, - layout: TyLayout<'tcx>, - offset: Size, - is_return: bool| { - // Booleans are always an i1 that needs to be zero-extended. - if scalar.is_bool() { - attrs.set(ArgAttribute::ZExt); - return; - } - - // Only pointer types handled below. - if scalar.value != Pointer { - return; - } - - if scalar.valid_range.start() < scalar.valid_range.end() { - if *scalar.valid_range.start() > 0 { - attrs.set(ArgAttribute::NonNull); - } - } - - if let Some(pointee) = layout.pointee_info_at(cx, offset) { - if let Some(kind) = pointee.safe { - attrs.pointee_align = Some(pointee.align); - - // `Box` (`UniqueBorrowed`) are not necessarily dereferencable - // for the entire duration of the function as they can be deallocated - // any time. Set their valid size to 0. - attrs.pointee_size = match kind { - PointerKind::UniqueOwned => Size::ZERO, - _ => pointee.size, - }; - - // `Box` pointer parameters never alias because ownership is transferred - // `&mut` pointer parameters never alias other parameters, - // or mutable global data - // - // `&T` where `T` contains no `UnsafeCell<U>` is immutable, - // and can be marked as both `readonly` and `noalias`, as - // LLVM's definition of `noalias` is based solely on memory - // dependencies rather than pointer equality - let no_alias = match kind { - PointerKind::Shared => false, - PointerKind::UniqueOwned => true, - PointerKind::Frozen | PointerKind::UniqueBorrowed => !is_return, - }; - if no_alias { - attrs.set(ArgAttribute::NoAlias); - } - - if kind == PointerKind::Frozen && !is_return { - attrs.set(ArgAttribute::ReadOnly); - } - } - } - }; - - let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| { - let is_return = arg_idx.is_none(); - let mut arg = mk_arg_type(ty, arg_idx); - if arg.layout.is_zst() { - // For some forsaken reason, x86_64-pc-windows-gnu - // doesn't ignore zero-sized struct arguments. - // The same is true for s390x-unknown-linux-gnu - // and sparc64-unknown-linux-gnu. - if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) { - arg.mode = PassMode::Ignore; - } - } - - // FIXME(eddyb) other ABIs don't have logic for scalar pairs. - if !is_return && rust_abi { - if let Abi::ScalarPair(ref a, ref b) = arg.layout.abi { - let mut a_attrs = ArgAttributes::new(); - let mut b_attrs = ArgAttributes::new(); - adjust_for_rust_scalar(&mut a_attrs, a, arg.layout, Size::ZERO, false); - adjust_for_rust_scalar( - &mut b_attrs, - b, - arg.layout, - a.value.size(cx).align_to(b.value.align(cx).abi), - false, - ); - arg.mode = PassMode::Pair(a_attrs, b_attrs); - return arg; - } - } - - if let Abi::Scalar(ref scalar) = arg.layout.abi { - if let PassMode::Direct(ref mut attrs) = arg.mode { - adjust_for_rust_scalar(attrs, scalar, arg.layout, Size::ZERO, is_return); - } - } - - arg - }; - - let mut fn_abi = FnAbi { - ret: arg_of(sig.output(), None), - args: inputs - .iter() - .cloned() - .chain(extra_args) - .chain(caller_location) - .enumerate() - .map(|(i, ty)| arg_of(ty, Some(i))) - .collect(), - c_variadic: sig.c_variadic, - fixed_count: inputs.len(), - conv, - }; - fn_abi.adjust_for_abi(cx, sig.abi); - fn_abi - } - - fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) { - if abi == SpecAbi::Unadjusted { - return; - } - - if abi == SpecAbi::Rust - || abi == SpecAbi::RustCall - || abi == SpecAbi::RustIntrinsic - || abi == SpecAbi::PlatformIntrinsic - { - let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>| { - if arg.is_ignore() { - return; - } - - match arg.layout.abi { - Abi::Aggregate { .. } => {} - - // This is a fun case! The gist of what this is doing is - // that we want callers and callees to always agree on the - // ABI of how they pass SIMD arguments. If we were to *not* - // make these arguments indirect then they'd be immediates - // in LLVM, which means that they'd used whatever the - // appropriate ABI is for the callee and the caller. That - // means, for example, if the caller doesn't have AVX - // enabled but the callee does, then passing an AVX argument - // across this boundary would cause corrupt data to show up. - // - // This problem is fixed by unconditionally passing SIMD - // arguments through memory between callers and callees - // which should get them all to agree on ABI regardless of - // target feature sets. Some more information about this - // issue can be found in #44367. - // - // Note that the platform intrinsic ABI is exempt here as - // that's how we connect up to LLVM and it's unstable - // anyway, we control all calls to it in libstd. - Abi::Vector { .. } - if abi != SpecAbi::PlatformIntrinsic - && cx.tcx().sess.target.target.options.simd_types_indirect => - { - arg.make_indirect(); - return; - } - - _ => return, - } - - let size = arg.layout.size; - if arg.layout.is_unsized() || size > Pointer.size(cx) { - arg.make_indirect(); - } else { - // We want to pass small aggregates as immediates, but using - // a LLVM aggregate type for this leads to bad optimizations, - // so we pick an appropriately sized integer type instead. - arg.cast_to(Reg { kind: RegKind::Integer, size }); - } - }; - fixup(&mut self.ret); - for arg in &mut self.args { - fixup(arg); - } - if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { - attrs.set(ArgAttribute::StructRet); - } - return; - } - - if let Err(msg) = self.adjust_for_cabi(cx, abi) { - cx.tcx().sess.fatal(&msg); - } - } -} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs deleted file mode 100644 index dae9f945ce0..00000000000 --- a/src/librustc/ty/mod.rs +++ /dev/null @@ -1,3169 +0,0 @@ -// ignore-tidy-filelength - -pub use self::fold::{TypeFoldable, TypeVisitor}; -pub use self::AssocItemContainer::*; -pub use self::BorrowKind::*; -pub use self::IntVarValue::*; -pub use self::Variance::*; - -use crate::arena::Arena; -use crate::hir::exports::ExportMap; -use crate::hir::map as hir_map; - -use crate::ich::Fingerprint; -use crate::ich::StableHashingContext; -use crate::infer::canonical::Canonical; -use crate::middle::cstore::CrateStoreDyn; -use crate::middle::lang_items::{FnMutTraitLangItem, FnOnceTraitLangItem, FnTraitLangItem}; -use crate::middle::resolve_lifetime::ObjectLifetimeDefault; -use crate::mir::interpret::ErrorHandled; -use crate::mir::GeneratorLayout; -use crate::mir::ReadOnlyBodyAndCache; -use crate::session::DataTypeKind; -use crate::traits::{self, Reveal}; -use crate::ty; -use crate::ty::layout::VariantIdx; -use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use crate::ty::util::{Discr, IntTypeExt}; -use crate::ty::walk::TypeWalker; -use rustc_attr as attr; -use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::sorted_map::SortedIndexMultiMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{self, par_iter, Lrc, ParallelIterator}; -use rustc_hir as hir; -use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_hir::{Constness, GlobMap, Node, TraitMap}; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_macros::HashStable; -use rustc_serialize::{self, Encodable, Encoder}; -use rustc_span::hygiene::ExpnId; -use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; -use rustc_target::abi::Align; -use syntax::ast::{self, Ident, Name}; -use syntax::node_id::{NodeId, NodeMap, NodeSet}; - -use std::cell::RefCell; -use std::cmp::{self, Ordering}; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::ops::Deref; -use std::ops::Range; -use std::slice; -use std::{mem, ptr}; - -pub use self::sty::BoundRegion::*; -pub use self::sty::InferTy::*; -pub use self::sty::RegionKind; -pub use self::sty::RegionKind::*; -pub use self::sty::TyKind::*; -pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNERMOST}; -pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; -pub use self::sty::{CanonicalPolyFnSig, FnSig, GenSig, PolyFnSig, PolyGenSig}; -pub use self::sty::{ClosureSubsts, GeneratorSubsts, TypeAndMut, UpvarSubsts}; -pub use self::sty::{Const, ConstKind, ExistentialProjection, PolyExistentialProjection}; -pub use self::sty::{ConstVid, FloatVid, IntVid, RegionVid, TyVid}; -pub use self::sty::{ExistentialPredicate, InferConst, InferTy, ParamConst, ParamTy, ProjectionTy}; -pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; -pub use self::sty::{PolyTraitRef, TraitRef, TyKind}; -pub use crate::ty::diagnostics::*; - -pub use self::binding::BindingMode; -pub use self::binding::BindingMode::*; - -pub use self::context::{keep_local, tls, FreeRegionInfo, TyCtxt}; -pub use self::context::{ - CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, ResolvedOpaqueTy, - UserType, UserTypeAnnotationIndex, -}; -pub use self::context::{ - CtxtInterners, GeneratorInteriorTypeCause, GlobalCtxt, Lift, TypeckTables, -}; - -pub use self::instance::RESOLVE_INSTANCE; -pub use self::instance::{Instance, InstanceDef}; - -pub use self::trait_def::TraitDef; - -pub use self::query::queries; - -pub mod adjustment; -pub mod binding; -pub mod cast; -#[macro_use] -pub mod codec; -pub mod _match; -mod erase_regions; -pub mod error; -pub mod fast_reject; -pub mod flags; -pub mod fold; -pub mod free_region_map; -pub mod inhabitedness; -pub mod layout; -pub mod normalize_erasing_regions; -pub mod outlives; -pub mod print; -pub mod query; -pub mod relate; -pub mod steal; -pub mod subst; -pub mod trait_def; -pub mod util; -pub mod walk; - -mod context; -mod diagnostics; -mod instance; -mod structural_impls; -mod sty; - -// Data types - -pub struct ResolverOutputs { - pub definitions: hir_map::Definitions, - pub cstore: Box<CrateStoreDyn>, - pub extern_crate_map: NodeMap<CrateNum>, - pub trait_map: TraitMap<NodeId>, - pub maybe_unused_trait_imports: NodeSet, - pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, - pub export_map: ExportMap<NodeId>, - pub glob_map: GlobMap, - /// Extern prelude entries. The value is `true` if the entry was introduced - /// via `extern crate` item and not `--extern` option or compiler built-in. - pub extern_prelude: FxHashMap<Name, bool>, -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)] -pub enum AssocItemContainer { - TraitContainer(DefId), - ImplContainer(DefId), -} - -impl AssocItemContainer { - /// Asserts that this is the `DefId` of an associated item declared - /// in a trait, and returns the trait `DefId`. - pub fn assert_trait(&self) -> DefId { - match *self { - TraitContainer(id) => id, - _ => bug!("associated item has wrong container type: {:?}", self), - } - } - - pub fn id(&self) -> DefId { - match *self { - TraitContainer(id) => id, - ImplContainer(id) => id, - } - } -} - -/// The "header" of an impl is everything outside the body: a Self type, a trait -/// ref (in the case of a trait impl), and a set of predicates (from the -/// bounds / where-clauses). -#[derive(Clone, Debug, TypeFoldable)] -pub struct ImplHeader<'tcx> { - pub impl_def_id: DefId, - pub self_ty: Ty<'tcx>, - pub trait_ref: Option<TraitRef<'tcx>>, - pub predicates: Vec<Predicate<'tcx>>, -} - -#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] -pub enum ImplPolarity { - /// `impl Trait for Type` - Positive, - /// `impl !Trait for Type` - Negative, - /// `#[rustc_reservation_impl] impl Trait for Type` - /// - /// This is a "stability hack", not a real Rust feature. - /// See #64631 for details. - Reservation, -} - -#[derive(Copy, Clone, Debug, PartialEq, HashStable)] -pub struct AssocItem { - pub def_id: DefId, - #[stable_hasher(project(name))] - pub ident: Ident, - pub kind: AssocKind, - pub vis: Visibility, - pub defaultness: hir::Defaultness, - pub container: AssocItemContainer, - - /// Whether this is a method with an explicit self - /// as its first argument, allowing method calls. - pub method_has_self_argument: bool, -} - -#[derive(Copy, Clone, PartialEq, Debug, HashStable)] -pub enum AssocKind { - Const, - Method, - OpaqueTy, - Type, -} - -impl AssocKind { - pub fn suggestion_descr(&self) -> &'static str { - match self { - ty::AssocKind::Method => "method call", - ty::AssocKind::Type | ty::AssocKind::OpaqueTy => "associated type", - ty::AssocKind::Const => "associated constant", - } - } - - pub fn namespace(&self) -> Namespace { - match *self { - ty::AssocKind::OpaqueTy | ty::AssocKind::Type => Namespace::TypeNS, - ty::AssocKind::Const | ty::AssocKind::Method => Namespace::ValueNS, - } - } -} - -impl AssocItem { - pub fn def_kind(&self) -> DefKind { - match self.kind { - AssocKind::Const => DefKind::AssocConst, - AssocKind::Method => DefKind::Method, - AssocKind::Type => DefKind::AssocTy, - AssocKind::OpaqueTy => DefKind::AssocOpaqueTy, - } - } - - /// Tests whether the associated item admits a non-trivial implementation - /// for ! - pub fn relevant_for_never(&self) -> bool { - match self.kind { - AssocKind::OpaqueTy | AssocKind::Const | AssocKind::Type => true, - // FIXME(canndrew): Be more thorough here, check if any argument is uninhabited. - AssocKind::Method => !self.method_has_self_argument, - } - } - - pub fn signature(&self, tcx: TyCtxt<'_>) -> String { - match self.kind { - ty::AssocKind::Method => { - // We skip the binder here because the binder would deanonymize all - // late-bound regions, and we don't want method signatures to show up - // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound - // regions just fine, showing `fn(&MyType)`. - tcx.fn_sig(self.def_id).skip_binder().to_string() - } - ty::AssocKind::Type => format!("type {};", self.ident), - // FIXME(type_alias_impl_trait): we should print bounds here too. - ty::AssocKind::OpaqueTy => format!("type {};", self.ident), - ty::AssocKind::Const => { - format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id)) - } - } - } -} - -/// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name. -/// -/// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since -/// it is relatively expensive. Instead, items are indexed by `Symbol` and hygienic comparison is -/// done only on items with the same name. -#[derive(Debug, Clone, PartialEq, HashStable)] -pub struct AssociatedItems { - items: SortedIndexMultiMap<u32, Symbol, ty::AssocItem>, -} - -impl AssociatedItems { - /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order. - pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self { - let items = items_in_def_order.into_iter().map(|item| (item.ident.name, item)).collect(); - AssociatedItems { items } - } - - /// Returns a slice of associated items in the order they were defined. - /// - /// New code should avoid relying on definition order. If you need a particular associated item - /// for a known trait, make that trait a lang item instead of indexing this array. - pub fn in_definition_order(&self) -> impl '_ + Iterator<Item = &ty::AssocItem> { - self.items.iter().map(|(_, v)| v) - } - - /// Returns an iterator over all associated items with the given name, ignoring hygiene. - pub fn filter_by_name_unhygienic( - &self, - name: Symbol, - ) -> impl '_ + Iterator<Item = &ty::AssocItem> { - self.items.get_by_key(&name) - } - - /// Returns an iterator over all associated items with the given name. - /// - /// Multiple items may have the same name if they are in different `Namespace`s. For example, - /// an associated type can have the same name as a method. Use one of the `find_by_name_and_*` - /// methods below if you know which item you are looking for. - pub fn filter_by_name( - &'a self, - tcx: TyCtxt<'a>, - ident: Ident, - parent_def_id: DefId, - ) -> impl 'a + Iterator<Item = &'a ty::AssocItem> { - self.filter_by_name_unhygienic(ident.name) - .filter(move |item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) - } - - /// Returns the associated item with the given name and `AssocKind`, if one exists. - pub fn find_by_name_and_kind( - &self, - tcx: TyCtxt<'_>, - ident: Ident, - kind: AssocKind, - parent_def_id: DefId, - ) -> Option<&ty::AssocItem> { - self.filter_by_name_unhygienic(ident.name) - .filter(|item| item.kind == kind) - .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) - } - - /// Returns the associated item with the given name in the given `Namespace`, if one exists. - pub fn find_by_name_and_namespace( - &self, - tcx: TyCtxt<'_>, - ident: Ident, - ns: Namespace, - parent_def_id: DefId, - ) -> Option<&ty::AssocItem> { - self.filter_by_name_unhygienic(ident.name) - .filter(|item| item.kind.namespace() == ns) - .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable)] -pub enum Visibility { - /// Visible everywhere (including in other crates). - Public, - /// Visible only in the given crate-local module. - Restricted(DefId), - /// Not visible anywhere in the local crate. This is the visibility of private external items. - Invisible, -} - -pub trait DefIdTree: Copy { - fn parent(self, id: DefId) -> Option<DefId>; - - fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool { - if descendant.krate != ancestor.krate { - return false; - } - - while descendant != ancestor { - match self.parent(descendant) { - Some(parent) => descendant = parent, - None => return false, - } - } - true - } -} - -impl<'tcx> DefIdTree for TyCtxt<'tcx> { - fn parent(self, id: DefId) -> Option<DefId> { - self.def_key(id).parent.map(|index| DefId { index: index, ..id }) - } -} - -impl Visibility { - pub fn from_hir(visibility: &hir::Visibility<'_>, id: hir::HirId, tcx: TyCtxt<'_>) -> Self { - match visibility.node { - hir::VisibilityKind::Public => Visibility::Public, - hir::VisibilityKind::Crate(_) => Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)), - hir::VisibilityKind::Restricted { ref path, .. } => match path.res { - // If there is no resolution, `resolve` will have already reported an error, so - // assume that the visibility is public to avoid reporting more privacy errors. - Res::Err => Visibility::Public, - def => Visibility::Restricted(def.def_id()), - }, - hir::VisibilityKind::Inherited => { - Visibility::Restricted(tcx.hir().get_module_parent(id)) - } - } - } - - /// Returns `true` if an item with this visibility is accessible from the given block. - pub fn is_accessible_from<T: DefIdTree>(self, module: DefId, tree: T) -> bool { - let restriction = match self { - // Public items are visible everywhere. - Visibility::Public => return true, - // Private items from other crates are visible nowhere. - Visibility::Invisible => return false, - // Restricted items are visible in an arbitrary local module. - Visibility::Restricted(other) if other.krate != module.krate => return false, - Visibility::Restricted(module) => module, - }; - - tree.is_descendant_of(module, restriction) - } - - /// Returns `true` if this visibility is at least as accessible as the given visibility - pub fn is_at_least<T: DefIdTree>(self, vis: Visibility, tree: T) -> bool { - let vis_restriction = match vis { - Visibility::Public => return self == Visibility::Public, - Visibility::Invisible => return true, - Visibility::Restricted(module) => module, - }; - - self.is_accessible_from(vis_restriction, tree) - } - - // Returns `true` if this item is visible anywhere in the local crate. - pub fn is_visible_locally(self) -> bool { - match self { - Visibility::Public => true, - Visibility::Restricted(def_id) => def_id.is_local(), - Visibility::Invisible => false, - } - } -} - -#[derive(Copy, Clone, PartialEq, RustcDecodable, RustcEncodable, HashStable)] -pub enum Variance { - Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type - Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell - Contravariant, // T<A> <: T<B> iff B <: A -- e.g., function param type - Bivariant, // T<A> <: T<B> -- e.g., unused type parameter -} - -/// The crate variances map is computed during typeck and contains the -/// variance of every item in the local crate. You should not use it -/// directly, because to do so will make your pass dependent on the -/// HIR of every item in the local crate. Instead, use -/// `tcx.variances_of()` to get the variance for a *particular* -/// item. -#[derive(HashStable)] -pub struct CrateVariancesMap<'tcx> { - /// For each item with generics, maps to a vector of the variance - /// of its generics. If an item has no generics, it will have no - /// entry. - pub variances: FxHashMap<DefId, &'tcx [ty::Variance]>, -} - -impl Variance { - /// `a.xform(b)` combines the variance of a context with the - /// variance of a type with the following meaning. If we are in a - /// context with variance `a`, and we encounter a type argument in - /// a position with variance `b`, then `a.xform(b)` is the new - /// variance with which the argument appears. - /// - /// Example 1: - /// - /// *mut Vec<i32> - /// - /// Here, the "ambient" variance starts as covariant. `*mut T` is - /// invariant with respect to `T`, so the variance in which the - /// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which - /// yields `Invariant`. Now, the type `Vec<T>` is covariant with - /// respect to its type argument `T`, and hence the variance of - /// the `i32` here is `Invariant.xform(Covariant)`, which results - /// (again) in `Invariant`. - /// - /// Example 2: - /// - /// fn(*const Vec<i32>, *mut Vec<i32) - /// - /// The ambient variance is covariant. A `fn` type is - /// contravariant with respect to its parameters, so the variance - /// within which both pointer types appear is - /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const - /// T` is covariant with respect to `T`, so the variance within - /// which the first `Vec<i32>` appears is - /// `Contravariant.xform(Covariant)` or `Contravariant`. The same - /// is true for its `i32` argument. In the `*mut T` case, the - /// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`, - /// and hence the outermost type is `Invariant` with respect to - /// `Vec<i32>` (and its `i32` argument). - /// - /// Source: Figure 1 of "Taming the Wildcards: - /// Combining Definition- and Use-Site Variance" published in PLDI'11. - pub fn xform(self, v: ty::Variance) -> ty::Variance { - match (self, v) { - // Figure 1, column 1. - (ty::Covariant, ty::Covariant) => ty::Covariant, - (ty::Covariant, ty::Contravariant) => ty::Contravariant, - (ty::Covariant, ty::Invariant) => ty::Invariant, - (ty::Covariant, ty::Bivariant) => ty::Bivariant, - - // Figure 1, column 2. - (ty::Contravariant, ty::Covariant) => ty::Contravariant, - (ty::Contravariant, ty::Contravariant) => ty::Covariant, - (ty::Contravariant, ty::Invariant) => ty::Invariant, - (ty::Contravariant, ty::Bivariant) => ty::Bivariant, - - // Figure 1, column 3. - (ty::Invariant, _) => ty::Invariant, - - // Figure 1, column 4. - (ty::Bivariant, _) => ty::Bivariant, - } - } -} - -// Contains information needed to resolve types and (in the future) look up -// the types of AST nodes. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct CReaderCacheKey { - pub cnum: CrateNum, - pub pos: usize, -} - -// Flags that we track on types. These flags are propagated upwards -// through the type during type construction, so that we can quickly -// check whether the type has various kinds of types in it without -// recursing over the type itself. -bitflags! { - pub struct TypeFlags: u32 { - const HAS_PARAMS = 1 << 0; - const HAS_TY_INFER = 1 << 1; - const HAS_RE_INFER = 1 << 2; - const HAS_RE_PLACEHOLDER = 1 << 3; - - /// Does this have any `ReEarlyBound` regions? Used to - /// determine whether substitition is required, since those - /// represent regions that are bound in a `ty::Generics` and - /// hence may be substituted. - const HAS_RE_EARLY_BOUND = 1 << 4; - - /// Does this have any region that "appears free" in the type? - /// Basically anything but `ReLateBound` and `ReErased`. - const HAS_FREE_REGIONS = 1 << 5; - - /// Is an error type reachable? - const HAS_TY_ERR = 1 << 6; - const HAS_PROJECTION = 1 << 7; - - // FIXME: Rename this to the actual property since it's used for generators too - const HAS_TY_CLOSURE = 1 << 8; - - /// `true` if there are "names" of types and regions and so forth - /// that are local to a particular fn - const HAS_FREE_LOCAL_NAMES = 1 << 9; - - /// Present if the type belongs in a local type context. - /// Only set for Infer other than Fresh. - const KEEP_IN_LOCAL_TCX = 1 << 10; - - /// Does this have any `ReLateBound` regions? Used to check - /// if a global bound is safe to evaluate. - const HAS_RE_LATE_BOUND = 1 << 11; - - /// Does this have any `ReErased` regions? - const HAS_RE_ERASED = 1 << 12; - - const HAS_TY_PLACEHOLDER = 1 << 13; - - const HAS_CT_INFER = 1 << 14; - const HAS_CT_PLACEHOLDER = 1 << 15; - /// Does this have any [Opaque] types. - const HAS_TY_OPAQUE = 1 << 16; - - const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | - TypeFlags::HAS_RE_EARLY_BOUND.bits; - - /// Flags representing the nominal content of a type, - /// computed by FlagsComputation. If you add a new nominal - /// flag, it should be added here too. - const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits | - TypeFlags::HAS_TY_INFER.bits | - TypeFlags::HAS_RE_INFER.bits | - TypeFlags::HAS_RE_PLACEHOLDER.bits | - TypeFlags::HAS_RE_EARLY_BOUND.bits | - TypeFlags::HAS_FREE_REGIONS.bits | - TypeFlags::HAS_TY_ERR.bits | - TypeFlags::HAS_PROJECTION.bits | - TypeFlags::HAS_TY_CLOSURE.bits | - TypeFlags::HAS_FREE_LOCAL_NAMES.bits | - TypeFlags::KEEP_IN_LOCAL_TCX.bits | - TypeFlags::HAS_RE_LATE_BOUND.bits | - TypeFlags::HAS_RE_ERASED.bits | - TypeFlags::HAS_TY_PLACEHOLDER.bits | - TypeFlags::HAS_CT_INFER.bits | - TypeFlags::HAS_CT_PLACEHOLDER.bits | - TypeFlags::HAS_TY_OPAQUE.bits; - } -} - -#[allow(rustc::usage_of_ty_tykind)] -pub struct TyS<'tcx> { - pub kind: TyKind<'tcx>, - pub flags: TypeFlags, - - /// This is a kind of confusing thing: it stores the smallest - /// binder such that - /// - /// (a) the binder itself captures nothing but - /// (b) all the late-bound things within the type are captured - /// by some sub-binder. - /// - /// So, for a type without any late-bound things, like `u32`, this - /// will be *innermost*, because that is the innermost binder that - /// captures nothing. But for a type `&'D u32`, where `'D` is a - /// late-bound region with De Bruijn index `D`, this would be `D + 1` - /// -- the binder itself does not capture `D`, but `D` is captured - /// by an inner binder. - /// - /// We call this concept an "exclusive" binder `D` because all - /// De Bruijn indices within the type are contained within `0..D` - /// (exclusive). - outer_exclusive_binder: ty::DebruijnIndex, -} - -// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(target_arch = "x86_64")] -static_assert_size!(TyS<'_>, 32); - -impl<'tcx> Ord for TyS<'tcx> { - fn cmp(&self, other: &TyS<'tcx>) -> Ordering { - self.kind.cmp(&other.kind) - } -} - -impl<'tcx> PartialOrd for TyS<'tcx> { - fn partial_cmp(&self, other: &TyS<'tcx>) -> Option<Ordering> { - Some(self.kind.cmp(&other.kind)) - } -} - -impl<'tcx> PartialEq for TyS<'tcx> { - #[inline] - fn eq(&self, other: &TyS<'tcx>) -> bool { - ptr::eq(self, other) - } -} -impl<'tcx> Eq for TyS<'tcx> {} - -impl<'tcx> Hash for TyS<'tcx> { - fn hash<H: Hasher>(&self, s: &mut H) { - (self as *const TyS<'_>).hash(s) - } -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::TyS<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let ty::TyS { - ref kind, - - // The other fields just provide fast access to information that is - // also contained in `kind`, so no need to hash them. - flags: _, - - outer_exclusive_binder: _, - } = *self; - - kind.hash_stable(hcx, hasher); - } -} - -#[rustc_diagnostic_item = "Ty"] -pub type Ty<'tcx> = &'tcx TyS<'tcx>; - -impl<'tcx> rustc_serialize::UseSpecializedEncodable for Ty<'tcx> {} -impl<'tcx> rustc_serialize::UseSpecializedDecodable for Ty<'tcx> {} - -pub type CanonicalTy<'tcx> = Canonical<'tcx, Ty<'tcx>>; - -extern "C" { - /// A dummy type used to force `List` to be unsized while not requiring references to it be wide - /// pointers. - type OpaqueListContents; -} - -/// A wrapper for slices with the additional invariant -/// that the slice is interned and no other slice with -/// the same contents can exist in the same context. -/// This means we can use pointer for both -/// equality comparisons and hashing. -/// Note: `Slice` was already taken by the `Ty`. -#[repr(C)] -pub struct List<T> { - len: usize, - data: [T; 0], - opaque: OpaqueListContents, -} - -unsafe impl<T: Sync> Sync for List<T> {} - -impl<T: Copy> List<T> { - #[inline] - fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx List<T> { - assert!(!mem::needs_drop::<T>()); - assert!(mem::size_of::<T>() != 0); - assert!(slice.len() != 0); - - // Align up the size of the len (usize) field - let align = mem::align_of::<T>(); - let align_mask = align - 1; - let offset = mem::size_of::<usize>(); - let offset = (offset + align_mask) & !align_mask; - - let size = offset + slice.len() * mem::size_of::<T>(); - - let mem = arena - .dropless - .alloc_raw(size, cmp::max(mem::align_of::<T>(), mem::align_of::<usize>())); - unsafe { - let result = &mut *(mem.as_mut_ptr() as *mut List<T>); - // Write the length - result.len = slice.len(); - - // Write the elements - let arena_slice = slice::from_raw_parts_mut(result.data.as_mut_ptr(), result.len); - arena_slice.copy_from_slice(slice); - - result - } - } -} - -impl<T: fmt::Debug> fmt::Debug for List<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -impl<T: Encodable> Encodable for List<T> { - #[inline] - fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { - (**self).encode(s) - } -} - -impl<T> Ord for List<T> -where - T: Ord, -{ - fn cmp(&self, other: &List<T>) -> Ordering { - if self == other { Ordering::Equal } else { <[T] as Ord>::cmp(&**self, &**other) } - } -} - -impl<T> PartialOrd for List<T> -where - T: PartialOrd, -{ - fn partial_cmp(&self, other: &List<T>) -> Option<Ordering> { - if self == other { - Some(Ordering::Equal) - } else { - <[T] as PartialOrd>::partial_cmp(&**self, &**other) - } - } -} - -impl<T: PartialEq> PartialEq for List<T> { - #[inline] - fn eq(&self, other: &List<T>) -> bool { - ptr::eq(self, other) - } -} -impl<T: Eq> Eq for List<T> {} - -impl<T> Hash for List<T> { - #[inline] - fn hash<H: Hasher>(&self, s: &mut H) { - (self as *const List<T>).hash(s) - } -} - -impl<T> Deref for List<T> { - type Target = [T]; - #[inline(always)] - fn deref(&self) -> &[T] { - self.as_ref() - } -} - -impl<T> AsRef<[T]> for List<T> { - #[inline(always)] - fn as_ref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) } - } -} - -impl<'a, T> IntoIterator for &'a List<T> { - type Item = &'a T; - type IntoIter = <&'a [T] as IntoIterator>::IntoIter; - #[inline(always)] - fn into_iter(self) -> Self::IntoIter { - self[..].iter() - } -} - -impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx List<Ty<'tcx>> {} - -impl<T> List<T> { - #[inline(always)] - pub fn empty<'a>() -> &'a List<T> { - #[repr(align(64), C)] - struct EmptySlice([u8; 64]); - static EMPTY_SLICE: EmptySlice = EmptySlice([0; 64]); - assert!(mem::align_of::<T>() <= 64); - unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] -pub struct UpvarPath { - pub hir_id: hir::HirId, -} - -/// Upvars do not get their own `NodeId`. Instead, we use the pair of -/// the original var ID (that is, the root variable that is referenced -/// by the upvar) and the ID of the closure expression. -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] -pub struct UpvarId { - pub var_path: UpvarPath, - pub closure_expr_id: LocalDefId, -} - -#[derive(Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, HashStable)] -pub enum BorrowKind { - /// Data must be immutable and is aliasable. - ImmBorrow, - - /// Data must be immutable but not aliasable. This kind of borrow - /// cannot currently be expressed by the user and is used only in - /// implicit closure bindings. It is needed when the closure - /// is borrowing or mutating a mutable referent, e.g.: - /// - /// let x: &mut isize = ...; - /// let y = || *x += 5; - /// - /// If we were to try to translate this closure into a more explicit - /// form, we'd encounter an error with the code as written: - /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } - /// - /// This is then illegal because you cannot mutate a `&mut` found - /// in an aliasable location. To solve, you'd have to translate with - /// an `&mut` borrow: - /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } - /// - /// Now the assignment to `**env.x` is legal, but creating a - /// mutable pointer to `x` is not because `x` is not mutable. We - /// could fix this by declaring `x` as `let mut x`. This is ok in - /// user code, if awkward, but extra weird for closures, since the - /// borrow is hidden. - /// - /// So we introduce a "unique imm" borrow -- the referent is - /// immutable, but not aliasable. This solves the problem. For - /// simplicity, we don't give users the way to express this - /// borrow, it's just used when translating closures. - UniqueImmBorrow, - - /// Data is mutable and not aliasable. - MutBorrow, -} - -/// Information describing the capture of an upvar. This is computed -/// during `typeck`, specifically by `regionck`. -#[derive(PartialEq, Clone, Debug, Copy, RustcEncodable, RustcDecodable, HashStable)] -pub enum UpvarCapture<'tcx> { - /// Upvar is captured by value. This is always true when the - /// closure is labeled `move`, but can also be true in other cases - /// depending on inference. - ByValue, - - /// Upvar is captured by reference. - ByRef(UpvarBorrow<'tcx>), -} - -#[derive(PartialEq, Clone, Copy, RustcEncodable, RustcDecodable, HashStable)] -pub struct UpvarBorrow<'tcx> { - /// The kind of borrow: by-ref upvars have access to shared - /// immutable borrows, which are not part of the normal language - /// syntax. - pub kind: BorrowKind, - - /// Region of the resulting reference. - pub region: ty::Region<'tcx>, -} - -pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>; -pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>; - -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum IntVarValue { - IntType(ast::IntTy), - UintType(ast::UintTy), -} - -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct FloatVarValue(pub ast::FloatTy); - -impl ty::EarlyBoundRegion { - pub fn to_bound_region(&self) -> ty::BoundRegion { - ty::BoundRegion::BrNamed(self.def_id, self.name) - } - - /// Does this early bound region have a name? Early bound regions normally - /// always have names except when using anonymous lifetimes (`'_`). - pub fn has_name(&self) -> bool { - self.name != kw::UnderscoreLifetime - } -} - -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub enum GenericParamDefKind { - Lifetime, - Type { - has_default: bool, - object_lifetime_default: ObjectLifetimeDefault, - synthetic: Option<hir::SyntheticTyParamKind>, - }, - Const, -} - -impl GenericParamDefKind { - pub fn descr(&self) -> &'static str { - match self { - GenericParamDefKind::Lifetime => "lifetime", - GenericParamDefKind::Type { .. } => "type", - GenericParamDefKind::Const => "constant", - } - } -} - -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct GenericParamDef { - pub name: Symbol, - pub def_id: DefId, - pub index: u32, - - /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute - /// on generic parameter `'a`/`T`, asserts data behind the parameter - /// `'a`/`T` won't be accessed during the parent type's `Drop` impl. - pub pure_wrt_drop: bool, - - pub kind: GenericParamDefKind, -} - -impl GenericParamDef { - pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion { - if let GenericParamDefKind::Lifetime = self.kind { - ty::EarlyBoundRegion { def_id: self.def_id, index: self.index, name: self.name } - } else { - bug!("cannot convert a non-lifetime parameter def to an early bound region") - } - } - - pub fn to_bound_region(&self) -> ty::BoundRegion { - if let GenericParamDefKind::Lifetime = self.kind { - self.to_early_bound_region_data().to_bound_region() - } else { - bug!("cannot convert a non-lifetime parameter def to an early bound region") - } - } -} - -#[derive(Default)] -pub struct GenericParamCount { - pub lifetimes: usize, - pub types: usize, - pub consts: usize, -} - -/// Information about the formal type/lifetime parameters associated -/// with an item or method. Analogous to `hir::Generics`. -/// -/// The ordering of parameters is the same as in `Subst` (excluding child generics): -/// `Self` (optionally), `Lifetime` params..., `Type` params... -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct Generics { - pub parent: Option<DefId>, - pub parent_count: usize, - pub params: Vec<GenericParamDef>, - - /// Reverse map to the `index` field of each `GenericParamDef`. - #[stable_hasher(ignore)] - pub param_def_id_to_index: FxHashMap<DefId, u32>, - - pub has_self: bool, - pub has_late_bound_regions: Option<Span>, -} - -impl<'tcx> Generics { - pub fn count(&self) -> usize { - self.parent_count + self.params.len() - } - - pub fn own_counts(&self) -> GenericParamCount { - // We could cache this as a property of `GenericParamCount`, but - // the aim is to refactor this away entirely eventually and the - // presence of this method will be a constant reminder. - let mut own_counts: GenericParamCount = Default::default(); - - for param in &self.params { - match param.kind { - GenericParamDefKind::Lifetime => own_counts.lifetimes += 1, - GenericParamDefKind::Type { .. } => own_counts.types += 1, - GenericParamDefKind::Const => own_counts.consts += 1, - }; - } - - own_counts - } - - pub fn requires_monomorphization(&self, tcx: TyCtxt<'tcx>) -> bool { - if self.own_requires_monomorphization() { - return true; - } - - if let Some(parent_def_id) = self.parent { - let parent = tcx.generics_of(parent_def_id); - parent.requires_monomorphization(tcx) - } else { - false - } - } - - pub fn own_requires_monomorphization(&self) -> bool { - for param in &self.params { - match param.kind { - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => return true, - GenericParamDefKind::Lifetime => {} - } - } - false - } - - pub fn region_param( - &'tcx self, - param: &EarlyBoundRegion, - tcx: TyCtxt<'tcx>, - ) -> &'tcx GenericParamDef { - if let Some(index) = param.index.checked_sub(self.parent_count as u32) { - let param = &self.params[index as usize]; - match param.kind { - GenericParamDefKind::Lifetime => param, - _ => bug!("expected lifetime parameter, but found another generic parameter"), - } - } else { - tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?")) - .region_param(param, tcx) - } - } - - /// Returns the `GenericParamDef` associated with this `ParamTy`. - pub fn type_param(&'tcx self, param: &ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef { - if let Some(index) = param.index.checked_sub(self.parent_count as u32) { - let param = &self.params[index as usize]; - match param.kind { - GenericParamDefKind::Type { .. } => param, - _ => bug!("expected type parameter, but found another generic parameter"), - } - } else { - tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?")) - .type_param(param, tcx) - } - } - - /// Returns the `ConstParameterDef` associated with this `ParamConst`. - pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef { - if let Some(index) = param.index.checked_sub(self.parent_count as u32) { - let param = &self.params[index as usize]; - match param.kind { - GenericParamDefKind::Const => param, - _ => bug!("expected const parameter, but found another generic parameter"), - } - } else { - tcx.generics_of(self.parent.expect("parent_count>0 but no parent?")) - .const_param(param, tcx) - } - } -} - -/// Bounds on generics. -#[derive(Copy, Clone, Default, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct GenericPredicates<'tcx> { - pub parent: Option<DefId>, - pub predicates: &'tcx [(Predicate<'tcx>, Span)], -} - -impl<'tcx> GenericPredicates<'tcx> { - pub fn instantiate( - &self, - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - ) -> InstantiatedPredicates<'tcx> { - let mut instantiated = InstantiatedPredicates::empty(); - self.instantiate_into(tcx, &mut instantiated, substs); - instantiated - } - - pub fn instantiate_own( - &self, - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - ) -> InstantiatedPredicates<'tcx> { - InstantiatedPredicates { - predicates: self.predicates.iter().map(|(p, _)| p.subst(tcx, substs)).collect(), - spans: self.predicates.iter().map(|(_, sp)| *sp).collect(), - } - } - - fn instantiate_into( - &self, - tcx: TyCtxt<'tcx>, - instantiated: &mut InstantiatedPredicates<'tcx>, - substs: SubstsRef<'tcx>, - ) { - if let Some(def_id) = self.parent { - tcx.predicates_of(def_id).instantiate_into(tcx, instantiated, substs); - } - instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p.subst(tcx, substs))); - instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp)); - } - - pub fn instantiate_identity(&self, tcx: TyCtxt<'tcx>) -> InstantiatedPredicates<'tcx> { - let mut instantiated = InstantiatedPredicates::empty(); - self.instantiate_identity_into(tcx, &mut instantiated); - instantiated - } - - fn instantiate_identity_into( - &self, - tcx: TyCtxt<'tcx>, - instantiated: &mut InstantiatedPredicates<'tcx>, - ) { - if let Some(def_id) = self.parent { - tcx.predicates_of(def_id).instantiate_identity_into(tcx, instantiated); - } - instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p)); - instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s)); - } - - pub fn instantiate_supertrait( - &self, - tcx: TyCtxt<'tcx>, - poly_trait_ref: &ty::PolyTraitRef<'tcx>, - ) -> InstantiatedPredicates<'tcx> { - assert_eq!(self.parent, None); - InstantiatedPredicates { - predicates: self - .predicates - .iter() - .map(|(pred, _)| pred.subst_supertrait(tcx, poly_trait_ref)) - .collect(), - spans: self.predicates.iter().map(|(_, sp)| *sp).collect(), - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable)] -pub enum Predicate<'tcx> { - /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be - /// the `Self` type of the trait reference and `A`, `B`, and `C` - /// would be the type parameters. - /// - /// A trait predicate will have `Constness::Const` if it originates - /// from a bound on a `const fn` without the `?const` opt-out (e.g., - /// `const fn foobar<Foo: Bar>() {}`). - Trait(PolyTraitPredicate<'tcx>, Constness), - - /// `where 'a: 'b` - RegionOutlives(PolyRegionOutlivesPredicate<'tcx>), - - /// `where T: 'a` - TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), - - /// `where <T as TraitRef>::Name == X`, approximately. - /// See the `ProjectionPredicate` struct for details. - Projection(PolyProjectionPredicate<'tcx>), - - /// No syntax: `T` well-formed. - WellFormed(Ty<'tcx>), - - /// Trait must be object-safe. - ObjectSafe(DefId), - - /// No direct syntax. May be thought of as `where T: FnFoo<...>` - /// for some substitutions `...` and `T` being a closure type. - /// Satisfied (or refuted) once we know the closure's kind. - ClosureKind(DefId, SubstsRef<'tcx>, ClosureKind), - - /// `T1 <: T2` - Subtype(PolySubtypePredicate<'tcx>), - - /// Constant initializer must evaluate successfully. - ConstEvaluatable(DefId, SubstsRef<'tcx>), -} - -/// The crate outlives map is computed during typeck and contains the -/// outlives of every item in the local crate. You should not use it -/// directly, because to do so will make your pass dependent on the -/// HIR of every item in the local crate. Instead, use -/// `tcx.inferred_outlives_of()` to get the outlives for a *particular* -/// item. -#[derive(HashStable)] -pub struct CratePredicatesMap<'tcx> { - /// For each struct with outlive bounds, maps to a vector of the - /// predicate of its outlive bounds. If an item has no outlives - /// bounds, it will have no entry. - pub predicates: FxHashMap<DefId, &'tcx [(ty::Predicate<'tcx>, Span)]>, -} - -impl<'tcx> AsRef<Predicate<'tcx>> for Predicate<'tcx> { - fn as_ref(&self) -> &Predicate<'tcx> { - self - } -} - -impl<'tcx> Predicate<'tcx> { - /// Performs a substitution suitable for going from a - /// poly-trait-ref to supertraits that must hold if that - /// poly-trait-ref holds. This is slightly different from a normal - /// substitution in terms of what happens with bound regions. See - /// lengthy comment below for details. - pub fn subst_supertrait( - &self, - tcx: TyCtxt<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, - ) -> ty::Predicate<'tcx> { - // The interaction between HRTB and supertraits is not entirely - // obvious. Let me walk you (and myself) through an example. - // - // Let's start with an easy case. Consider two traits: - // - // trait Foo<'a>: Bar<'a,'a> { } - // trait Bar<'b,'c> { } - // - // Now, if we have a trait reference `for<'x> T: Foo<'x>`, then - // we can deduce that `for<'x> T: Bar<'x,'x>`. Basically, if we - // knew that `Foo<'x>` (for any 'x) then we also know that - // `Bar<'x,'x>` (for any 'x). This more-or-less falls out from - // normal substitution. - // - // In terms of why this is sound, the idea is that whenever there - // is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>` - // holds. So if there is an impl of `T:Foo<'a>` that applies to - // all `'a`, then we must know that `T:Bar<'a,'a>` holds for all - // `'a`. - // - // Another example to be careful of is this: - // - // trait Foo1<'a>: for<'b> Bar1<'a,'b> { } - // trait Bar1<'b,'c> { } - // - // Here, if we have `for<'x> T: Foo1<'x>`, then what do we know? - // The answer is that we know `for<'x,'b> T: Bar1<'x,'b>`. The - // reason is similar to the previous example: any impl of - // `T:Foo1<'x>` must show that `for<'b> T: Bar1<'x, 'b>`. So - // basically we would want to collapse the bound lifetimes from - // the input (`trait_ref`) and the supertraits. - // - // To achieve this in practice is fairly straightforward. Let's - // consider the more complicated scenario: - // - // - We start out with `for<'x> T: Foo1<'x>`. In this case, `'x` - // has a De Bruijn index of 1. We want to produce `for<'x,'b> T: Bar1<'x,'b>`, - // where both `'x` and `'b` would have a DB index of 1. - // The substitution from the input trait-ref is therefore going to be - // `'a => 'x` (where `'x` has a DB index of 1). - // - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an - // early-bound parameter and `'b' is a late-bound parameter with a - // DB index of 1. - // - If we replace `'a` with `'x` from the input, it too will have - // a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>` - // just as we wanted. - // - // There is only one catch. If we just apply the substitution `'a - // => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will - // adjust the DB index because we substituting into a binder (it - // tries to be so smart...) resulting in `for<'x> for<'b> - // Bar1<'x,'b>` (we have no syntax for this, so use your - // imagination). Basically the 'x will have DB index of 2 and 'b - // will have DB index of 1. Not quite what we want. So we apply - // the substitution to the *contents* of the trait reference, - // rather than the trait reference itself (put another way, the - // substitution code expects equal binding levels in the values - // from the substitution and the value being substituted into, and - // this trick achieves that). - - let substs = &trait_ref.skip_binder().substs; - match *self { - Predicate::Trait(ref binder, constness) => { - Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness) - } - Predicate::Subtype(ref binder) => { - Predicate::Subtype(binder.map_bound(|data| data.subst(tcx, substs))) - } - Predicate::RegionOutlives(ref binder) => { - Predicate::RegionOutlives(binder.map_bound(|data| data.subst(tcx, substs))) - } - Predicate::TypeOutlives(ref binder) => { - Predicate::TypeOutlives(binder.map_bound(|data| data.subst(tcx, substs))) - } - Predicate::Projection(ref binder) => { - Predicate::Projection(binder.map_bound(|data| data.subst(tcx, substs))) - } - Predicate::WellFormed(data) => Predicate::WellFormed(data.subst(tcx, substs)), - Predicate::ObjectSafe(trait_def_id) => Predicate::ObjectSafe(trait_def_id), - Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - Predicate::ClosureKind(closure_def_id, closure_substs.subst(tcx, substs), kind) - } - Predicate::ConstEvaluatable(def_id, const_substs) => { - Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)) - } - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable)] -pub struct TraitPredicate<'tcx> { - pub trait_ref: TraitRef<'tcx>, -} - -pub type PolyTraitPredicate<'tcx> = ty::Binder<TraitPredicate<'tcx>>; - -impl<'tcx> TraitPredicate<'tcx> { - pub fn def_id(&self) -> DefId { - self.trait_ref.def_id - } - - pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a { - self.trait_ref.input_types() - } - - pub fn self_ty(&self) -> Ty<'tcx> { - self.trait_ref.self_ty() - } -} - -impl<'tcx> PolyTraitPredicate<'tcx> { - pub fn def_id(&self) -> DefId { - // Ok to skip binder since trait `DefId` does not care about regions. - self.skip_binder().def_id() - } -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable)] -pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B` -pub type PolyOutlivesPredicate<A, B> = ty::Binder<OutlivesPredicate<A, B>>; -pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>; -pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>; -pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<RegionOutlivesPredicate<'tcx>>; -pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<TypeOutlivesPredicate<'tcx>>; - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable)] -pub struct SubtypePredicate<'tcx> { - pub a_is_expected: bool, - pub a: Ty<'tcx>, - pub b: Ty<'tcx>, -} -pub type PolySubtypePredicate<'tcx> = ty::Binder<SubtypePredicate<'tcx>>; - -/// This kind of predicate has no *direct* correspondent in the -/// syntax, but it roughly corresponds to the syntactic forms: -/// -/// 1. `T: TraitRef<..., Item = Type>` -/// 2. `<T as TraitRef<...>>::Item == Type` (NYI) -/// -/// In particular, form #1 is "desugared" to the combination of a -/// normal trait predicate (`T: TraitRef<...>`) and one of these -/// predicates. Form #2 is a broader form in that it also permits -/// equality between arbitrary types. Processing an instance of -/// Form #2 eventually yields one of these `ProjectionPredicate` -/// instances to normalize the LHS. -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable)] -pub struct ProjectionPredicate<'tcx> { - pub projection_ty: ProjectionTy<'tcx>, - pub ty: Ty<'tcx>, -} - -pub type PolyProjectionPredicate<'tcx> = Binder<ProjectionPredicate<'tcx>>; - -impl<'tcx> PolyProjectionPredicate<'tcx> { - /// Returns the `DefId` of the associated item being projected. - pub fn item_def_id(&self) -> DefId { - self.skip_binder().projection_ty.item_def_id - } - - #[inline] - pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> { - // Note: unlike with `TraitRef::to_poly_trait_ref()`, - // `self.0.trait_ref` is permitted to have escaping regions. - // This is because here `self` has a `Binder` and so does our - // return value, so we are preserving the number of binding - // levels. - self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx)) - } - - pub fn ty(&self) -> Binder<Ty<'tcx>> { - self.map_bound(|predicate| predicate.ty) - } - - /// The `DefId` of the `TraitItem` for the associated type. - /// - /// Note that this is not the `DefId` of the `TraitRef` containing this - /// associated type, which is in `tcx.associated_item(projection_def_id()).container`. - pub fn projection_def_id(&self) -> DefId { - // Ok to skip binder since trait `DefId` does not care about regions. - self.skip_binder().projection_ty.item_def_id - } -} - -pub trait ToPolyTraitRef<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; -} - -impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - ty::Binder::dummy(*self) - } -} - -impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - self.map_bound_ref(|trait_pred| trait_pred.trait_ref) - } -} - -pub trait ToPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx>; -} - -impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> { - fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait( - ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value }), - self.constness, - ) - } -} - -impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> { - fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait( - ty::Binder::dummy(ty::TraitPredicate { trait_ref: *self.value }), - self.constness, - ) - } -} - -impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> { - fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness) - } -} - -impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&PolyTraitRef<'tcx>> { - fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::RegionOutlives(*self) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::TypeOutlives(*self) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::Projection(*self) - } -} - -// A custom iterator used by `Predicate::walk_tys`. -enum WalkTysIter<'tcx, I, J, K> -where - I: Iterator<Item = Ty<'tcx>>, - J: Iterator<Item = Ty<'tcx>>, - K: Iterator<Item = Ty<'tcx>>, -{ - None, - One(Ty<'tcx>), - Two(Ty<'tcx>, Ty<'tcx>), - Types(I), - InputTypes(J), - ProjectionTypes(K), -} - -impl<'tcx, I, J, K> Iterator for WalkTysIter<'tcx, I, J, K> -where - I: Iterator<Item = Ty<'tcx>>, - J: Iterator<Item = Ty<'tcx>>, - K: Iterator<Item = Ty<'tcx>>, -{ - type Item = Ty<'tcx>; - - fn next(&mut self) -> Option<Ty<'tcx>> { - match *self { - WalkTysIter::None => None, - WalkTysIter::One(item) => { - *self = WalkTysIter::None; - Some(item) - } - WalkTysIter::Two(item1, item2) => { - *self = WalkTysIter::One(item2); - Some(item1) - } - WalkTysIter::Types(ref mut iter) => iter.next(), - WalkTysIter::InputTypes(ref mut iter) => iter.next(), - WalkTysIter::ProjectionTypes(ref mut iter) => iter.next(), - } - } -} - -impl<'tcx> Predicate<'tcx> { - /// Iterates over the types in this predicate. Note that in all - /// cases this is skipping over a binder, so late-bound regions - /// with depth 0 are bound by the predicate. - pub fn walk_tys(&'a self) -> impl Iterator<Item = Ty<'tcx>> + 'a { - match *self { - ty::Predicate::Trait(ref data, _) => { - WalkTysIter::InputTypes(data.skip_binder().input_types()) - } - ty::Predicate::Subtype(binder) => { - let SubtypePredicate { a, b, a_is_expected: _ } = binder.skip_binder(); - WalkTysIter::Two(a, b) - } - ty::Predicate::TypeOutlives(binder) => WalkTysIter::One(binder.skip_binder().0), - ty::Predicate::RegionOutlives(..) => WalkTysIter::None, - ty::Predicate::Projection(ref data) => { - let inner = data.skip_binder(); - WalkTysIter::ProjectionTypes( - inner.projection_ty.substs.types().chain(Some(inner.ty)), - ) - } - ty::Predicate::WellFormed(data) => WalkTysIter::One(data), - ty::Predicate::ObjectSafe(_trait_def_id) => WalkTysIter::None, - ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) => { - WalkTysIter::Types(closure_substs.types()) - } - ty::Predicate::ConstEvaluatable(_, substs) => WalkTysIter::Types(substs.types()), - } - } - - pub fn to_opt_poly_trait_ref(&self) -> Option<PolyTraitRef<'tcx>> { - match *self { - Predicate::Trait(ref t, _) => Some(t.to_poly_trait_ref()), - Predicate::Projection(..) - | Predicate::Subtype(..) - | Predicate::RegionOutlives(..) - | Predicate::WellFormed(..) - | Predicate::ObjectSafe(..) - | Predicate::ClosureKind(..) - | Predicate::TypeOutlives(..) - | Predicate::ConstEvaluatable(..) => None, - } - } - - pub fn to_opt_type_outlives(&self) -> Option<PolyTypeOutlivesPredicate<'tcx>> { - match *self { - Predicate::TypeOutlives(data) => Some(data), - Predicate::Trait(..) - | Predicate::Projection(..) - | Predicate::Subtype(..) - | Predicate::RegionOutlives(..) - | Predicate::WellFormed(..) - | Predicate::ObjectSafe(..) - | Predicate::ClosureKind(..) - | Predicate::ConstEvaluatable(..) => None, - } - } -} - -/// Represents the bounds declared on a particular set of type -/// parameters. Should eventually be generalized into a flag list of -/// where-clauses. You can obtain a `InstantiatedPredicates` list from a -/// `GenericPredicates` by using the `instantiate` method. Note that this method -/// reflects an important semantic invariant of `InstantiatedPredicates`: while -/// the `GenericPredicates` are expressed in terms of the bound type -/// parameters of the impl/trait/whatever, an `InstantiatedPredicates` instance -/// represented a set of bounds for some particular instantiation, -/// meaning that the generic parameters have been substituted with -/// their values. -/// -/// Example: -/// -/// struct Foo<T, U: Bar<T>> { ... } -/// -/// Here, the `GenericPredicates` for `Foo` would contain a list of bounds like -/// `[[], [U:Bar<T>]]`. Now if there were some particular reference -/// like `Foo<isize,usize>`, then the `InstantiatedPredicates` would be `[[], -/// [usize:Bar<isize>]]`. -#[derive(Clone, Debug, TypeFoldable)] -pub struct InstantiatedPredicates<'tcx> { - pub predicates: Vec<Predicate<'tcx>>, - pub spans: Vec<Span>, -} - -impl<'tcx> InstantiatedPredicates<'tcx> { - pub fn empty() -> InstantiatedPredicates<'tcx> { - InstantiatedPredicates { predicates: vec![], spans: vec![] } - } - - pub fn is_empty(&self) -> bool { - self.predicates.is_empty() - } -} - -rustc_index::newtype_index! { - /// "Universes" are used during type- and trait-checking in the - /// presence of `for<..>` binders to control what sets of names are - /// visible. Universes are arranged into a tree: the root universe - /// contains names that are always visible. Each child then adds a new - /// set of names that are visible, in addition to those of its parent. - /// We say that the child universe "extends" the parent universe with - /// new names. - /// - /// To make this more concrete, consider this program: - /// - /// ``` - /// struct Foo { } - /// fn bar<T>(x: T) { - /// let y: for<'a> fn(&'a u8, Foo) = ...; - /// } - /// ``` - /// - /// The struct name `Foo` is in the root universe U0. But the type - /// parameter `T`, introduced on `bar`, is in an extended universe U1 - /// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside - /// of `bar`, we cannot name `T`. Then, within the type of `y`, the - /// region `'a` is in a universe U2 that extends U1, because we can - /// name it inside the fn type but not outside. - /// - /// Universes are used to do type- and trait-checking around these - /// "forall" binders (also called **universal quantification**). The - /// idea is that when, in the body of `bar`, we refer to `T` as a - /// type, we aren't referring to any type in particular, but rather a - /// kind of "fresh" type that is distinct from all other types we have - /// actually declared. This is called a **placeholder** type, and we - /// use universes to talk about this. In other words, a type name in - /// universe 0 always corresponds to some "ground" type that the user - /// declared, but a type name in a non-zero universe is a placeholder - /// type -- an idealized representative of "types in general" that we - /// use for checking generic functions. - pub struct UniverseIndex { - derive [HashStable] - DEBUG_FORMAT = "U{}", - } -} - -impl UniverseIndex { - pub const ROOT: UniverseIndex = UniverseIndex::from_u32_const(0); - - /// Returns the "next" universe index in order -- this new index - /// is considered to extend all previous universes. This - /// corresponds to entering a `forall` quantifier. So, for - /// example, suppose we have this type in universe `U`: - /// - /// ``` - /// for<'a> fn(&'a u32) - /// ``` - /// - /// Once we "enter" into this `for<'a>` quantifier, we are in a - /// new universe that extends `U` -- in this new universe, we can - /// name the region `'a`, but that region was not nameable from - /// `U` because it was not in scope there. - pub fn next_universe(self) -> UniverseIndex { - UniverseIndex::from_u32(self.private.checked_add(1).unwrap()) - } - - /// Returns `true` if `self` can name a name from `other` -- in other words, - /// if the set of names in `self` is a superset of those in - /// `other` (`self >= other`). - pub fn can_name(self, other: UniverseIndex) -> bool { - self.private >= other.private - } - - /// Returns `true` if `self` cannot name some names from `other` -- in other - /// words, if the set of names in `self` is a strict subset of - /// those in `other` (`self < other`). - pub fn cannot_name(self, other: UniverseIndex) -> bool { - self.private < other.private - } -} - -/// The "placeholder index" fully defines a placeholder region. -/// Placeholder regions are identified by both a **universe** as well -/// as a "bound-region" within that universe. The `bound_region` is -/// basically a name -- distinct bound regions within the same -/// universe are just two regions with an unknown relationship to one -/// another. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, PartialOrd, Ord)] -pub struct Placeholder<T> { - pub universe: UniverseIndex, - pub name: T, -} - -impl<'a, T> HashStable<StableHashingContext<'a>> for Placeholder<T> -where - T: HashStable<StableHashingContext<'a>>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.universe.hash_stable(hcx, hasher); - self.name.hash_stable(hcx, hasher); - } -} - -pub type PlaceholderRegion = Placeholder<BoundRegion>; - -pub type PlaceholderType = Placeholder<BoundVar>; - -pub type PlaceholderConst = Placeholder<BoundVar>; - -/// When type checking, we use the `ParamEnv` to track -/// details about the set of where-clauses that are in scope at this -/// particular point. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TypeFoldable)] -pub struct ParamEnv<'tcx> { - /// `Obligation`s that the caller must satisfy. This is basically - /// the set of bounds on the in-scope type parameters, translated - /// into `Obligation`s, and elaborated and normalized. - pub caller_bounds: &'tcx List<ty::Predicate<'tcx>>, - - /// Typically, this is `Reveal::UserFacing`, but during codegen we - /// want `Reveal::All` -- note that this is always paired with an - /// empty environment. To get that, use `ParamEnv::reveal()`. - pub reveal: traits::Reveal, - - /// If this `ParamEnv` comes from a call to `tcx.param_env(def_id)`, - /// register that `def_id` (useful for transitioning to the chalk trait - /// solver). - pub def_id: Option<DefId>, -} - -impl<'tcx> ParamEnv<'tcx> { - /// Construct a trait environment suitable for contexts where - /// there are no where-clauses in scope. Hidden types (like `impl - /// Trait`) are left hidden, so this is suitable for ordinary - /// type-checking. - #[inline] - pub fn empty() -> Self { - Self::new(List::empty(), Reveal::UserFacing, None) - } - - /// Construct a trait environment with no where-clauses in scope - /// where the values of all `impl Trait` and other hidden types - /// are revealed. This is suitable for monomorphized, post-typeck - /// environments like codegen or doing optimizations. - /// - /// N.B., if you want to have predicates in scope, use `ParamEnv::new`, - /// or invoke `param_env.with_reveal_all()`. - #[inline] - pub fn reveal_all() -> Self { - Self::new(List::empty(), Reveal::All, None) - } - - /// Construct a trait environment with the given set of predicates. - #[inline] - pub fn new( - caller_bounds: &'tcx List<ty::Predicate<'tcx>>, - reveal: Reveal, - def_id: Option<DefId>, - ) -> Self { - ty::ParamEnv { caller_bounds, reveal, def_id } - } - - /// Returns a new parameter environment with the same clauses, but - /// which "reveals" the true results of projections in all cases - /// (even for associated types that are specializable). This is - /// the desired behavior during codegen and certain other special - /// contexts; normally though we want to use `Reveal::UserFacing`, - /// which is the default. - pub fn with_reveal_all(self) -> Self { - ty::ParamEnv { reveal: Reveal::All, ..self } - } - - /// Returns this same environment but with no caller bounds. - pub fn without_caller_bounds(self) -> Self { - ty::ParamEnv { caller_bounds: List::empty(), ..self } - } - - /// Creates a suitable environment in which to perform trait - /// queries on the given value. When type-checking, this is simply - /// the pair of the environment plus value. But when reveal is set to - /// All, then if `value` does not reference any type parameters, we will - /// pair it with the empty environment. This improves caching and is generally - /// invisible. - /// - /// N.B., we preserve the environment when type-checking because it - /// is possible for the user to have wacky where-clauses like - /// `where Box<u32>: Copy`, which are clearly never - /// satisfiable. We generally want to behave as if they were true, - /// although the surrounding function is never reachable. - pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> { - match self.reveal { - Reveal::UserFacing => ParamEnvAnd { param_env: self, value }, - - Reveal::All => { - if value.has_placeholders() || value.needs_infer() || value.has_param_types() { - ParamEnvAnd { param_env: self, value } - } else { - ParamEnvAnd { param_env: self.without_caller_bounds(), value } - } - } - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct ConstnessAnd<T> { - pub constness: Constness, - pub value: T, -} - -// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate()` to ensure that -// the constness of trait bounds is being propagated correctly. -pub trait WithConstness: Sized { - #[inline] - fn with_constness(self, constness: Constness) -> ConstnessAnd<Self> { - ConstnessAnd { constness, value: self } - } - - #[inline] - fn with_const(self) -> ConstnessAnd<Self> { - self.with_constness(Constness::Const) - } - - #[inline] - fn without_const(self) -> ConstnessAnd<Self> { - self.with_constness(Constness::NotConst) - } -} - -impl<T> WithConstness for T {} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)] -pub struct ParamEnvAnd<'tcx, T> { - pub param_env: ParamEnv<'tcx>, - pub value: T, -} - -impl<'tcx, T> ParamEnvAnd<'tcx, T> { - pub fn into_parts(self) -> (ParamEnv<'tcx>, T) { - (self.param_env, self.value) - } -} - -impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for ParamEnvAnd<'tcx, T> -where - T: HashStable<StableHashingContext<'a>>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let ParamEnvAnd { ref param_env, ref value } = *self; - - param_env.hash_stable(hcx, hasher); - value.hash_stable(hcx, hasher); - } -} - -#[derive(Copy, Clone, Debug, HashStable)] -pub struct Destructor { - /// The `DefId` of the destructor method - pub did: DefId, -} - -bitflags! { - #[derive(HashStable)] - pub struct AdtFlags: u32 { - const NO_ADT_FLAGS = 0; - /// Indicates whether the ADT is an enum. - const IS_ENUM = 1 << 0; - /// Indicates whether the ADT is a union. - const IS_UNION = 1 << 1; - /// Indicates whether the ADT is a struct. - const IS_STRUCT = 1 << 2; - /// Indicates whether the ADT is a struct and has a constructor. - const HAS_CTOR = 1 << 3; - /// Indicates whether the type is `PhantomData`. - const IS_PHANTOM_DATA = 1 << 4; - /// Indicates whether the type has a `#[fundamental]` attribute. - const IS_FUNDAMENTAL = 1 << 5; - /// Indicates whether the type is `Box`. - const IS_BOX = 1 << 6; - /// Indicates whether the type is `ManuallyDrop`. - const IS_MANUALLY_DROP = 1 << 7; - // FIXME(matthewjasper) replace these with diagnostic items - /// Indicates whether the type is an `Arc`. - const IS_ARC = 1 << 8; - /// Indicates whether the type is an `Rc`. - const IS_RC = 1 << 9; - /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`. - /// (i.e., this flag is never set unless this ADT is an enum). - const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 10; - } -} - -bitflags! { - #[derive(HashStable)] - pub struct VariantFlags: u32 { - const NO_VARIANT_FLAGS = 0; - /// Indicates whether the field list of this variant is `#[non_exhaustive]`. - const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0; - } -} - -/// Definition of a variant -- a struct's fields or a enum variant. -#[derive(Debug, HashStable)] -pub struct VariantDef { - /// `DefId` that identifies the variant itself. - /// If this variant belongs to a struct or union, then this is a copy of its `DefId`. - pub def_id: DefId, - /// `DefId` that identifies the variant's constructor. - /// If this variant is a struct variant, then this is `None`. - pub ctor_def_id: Option<DefId>, - /// Variant or struct name. - #[stable_hasher(project(name))] - pub ident: Ident, - /// Discriminant of this variant. - pub discr: VariantDiscr, - /// Fields of this variant. - pub fields: Vec<FieldDef>, - /// Type of constructor of variant. - pub ctor_kind: CtorKind, - /// Flags of the variant (e.g. is field list non-exhaustive)? - flags: VariantFlags, - /// Variant is obtained as part of recovering from a syntactic error. - /// May be incomplete or bogus. - pub recovered: bool, -} - -impl<'tcx> VariantDef { - /// Creates a new `VariantDef`. - /// - /// `variant_did` is the `DefId` that identifies the enum variant (if this `VariantDef` - /// represents an enum variant). - /// - /// `ctor_did` is the `DefId` that identifies the constructor of unit or - /// tuple-variants/structs. If this is a `struct`-variant then this should be `None`. - /// - /// `parent_did` is the `DefId` of the `AdtDef` representing the enum or struct that - /// owns this variant. It is used for checking if a struct has `#[non_exhaustive]` w/out having - /// to go through the redirect of checking the ctor's attributes - but compiling a small crate - /// requires loading the `AdtDef`s for all the structs in the universe (e.g., coherence for any - /// built-in trait), and we do not want to load attributes twice. - /// - /// If someone speeds up attribute loading to not be a performance concern, they can - /// remove this hack and use the constructor `DefId` everywhere. - pub fn new( - tcx: TyCtxt<'tcx>, - ident: Ident, - variant_did: Option<DefId>, - ctor_def_id: Option<DefId>, - discr: VariantDiscr, - fields: Vec<FieldDef>, - ctor_kind: CtorKind, - adt_kind: AdtKind, - parent_did: DefId, - recovered: bool, - ) -> Self { - debug!( - "VariantDef::new(ident = {:?}, variant_did = {:?}, ctor_def_id = {:?}, discr = {:?}, - fields = {:?}, ctor_kind = {:?}, adt_kind = {:?}, parent_did = {:?})", - ident, variant_did, ctor_def_id, discr, fields, ctor_kind, adt_kind, parent_did, - ); - - let mut flags = VariantFlags::NO_VARIANT_FLAGS; - if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive) { - debug!("found non-exhaustive field list for {:?}", parent_did); - flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; - } else if let Some(variant_did) = variant_did { - if tcx.has_attr(variant_did, sym::non_exhaustive) { - debug!("found non-exhaustive field list for {:?}", variant_did); - flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; - } - } - - VariantDef { - def_id: variant_did.unwrap_or(parent_did), - ctor_def_id, - ident, - discr, - fields, - ctor_kind, - flags, - recovered, - } - } - - /// Is this field list non-exhaustive? - #[inline] - pub fn is_field_list_non_exhaustive(&self) -> bool { - self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE) - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] -pub enum VariantDiscr { - /// Explicit value for this variant, i.e., `X = 123`. - /// The `DefId` corresponds to the embedded constant. - Explicit(DefId), - - /// The previous variant's discriminant plus one. - /// For efficiency reasons, the distance from the - /// last `Explicit` discriminant is being stored, - /// or `0` for the first variant, if it has none. - Relative(u32), -} - -#[derive(Debug, HashStable)] -pub struct FieldDef { - pub did: DefId, - #[stable_hasher(project(name))] - pub ident: Ident, - pub vis: Visibility, -} - -/// The definition of a user-defined type, e.g., a `struct`, `enum`, or `union`. -/// -/// These are all interned (by `intern_adt_def`) into the `adt_defs` table. -/// -/// The initialism *ADT* stands for an [*algebraic data type (ADT)*][adt]. -/// This is slightly wrong because `union`s are not ADTs. -/// Moreover, Rust only allows recursive data types through indirection. -/// -/// [adt]: https://en.wikipedia.org/wiki/Algebraic_data_type -pub struct AdtDef { - /// The `DefId` of the struct, enum or union item. - pub did: DefId, - /// Variants of the ADT. If this is a struct or union, then there will be a single variant. - pub variants: IndexVec<self::layout::VariantIdx, VariantDef>, - /// Flags of the ADT (e.g., is this a struct? is this non-exhaustive?). - flags: AdtFlags, - /// Repr options provided by the user. - pub repr: ReprOptions, -} - -impl PartialOrd for AdtDef { - fn partial_cmp(&self, other: &AdtDef) -> Option<Ordering> { - Some(self.cmp(&other)) - } -} - -/// There should be only one AdtDef for each `did`, therefore -/// it is fine to implement `Ord` only based on `did`. -impl Ord for AdtDef { - fn cmp(&self, other: &AdtDef) -> Ordering { - self.did.cmp(&other.did) - } -} - -impl PartialEq for AdtDef { - // `AdtDef`s are always interned, and this is part of `TyS` equality. - #[inline] - fn eq(&self, other: &Self) -> bool { - ptr::eq(self, other) - } -} - -impl Eq for AdtDef {} - -impl Hash for AdtDef { - #[inline] - fn hash<H: Hasher>(&self, s: &mut H) { - (self as *const AdtDef).hash(s) - } -} - -impl<'tcx> rustc_serialize::UseSpecializedEncodable for &'tcx AdtDef { - fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { - self.did.encode(s) - } -} - -impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx AdtDef {} - -impl<'a> HashStable<StableHashingContext<'a>> for AdtDef { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - thread_local! { - static CACHE: RefCell<FxHashMap<usize, Fingerprint>> = Default::default(); - } - - let hash: Fingerprint = CACHE.with(|cache| { - let addr = self as *const AdtDef as usize; - *cache.borrow_mut().entry(addr).or_insert_with(|| { - let ty::AdtDef { did, ref variants, ref flags, ref repr } = *self; - - let mut hasher = StableHasher::new(); - did.hash_stable(hcx, &mut hasher); - variants.hash_stable(hcx, &mut hasher); - flags.hash_stable(hcx, &mut hasher); - repr.hash_stable(hcx, &mut hasher); - - hasher.finish() - }) - }); - - hash.hash_stable(hcx, hasher); - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -pub enum AdtKind { - Struct, - Union, - Enum, -} - -impl Into<DataTypeKind> for AdtKind { - fn into(self) -> DataTypeKind { - match self { - AdtKind::Struct => DataTypeKind::Struct, - AdtKind::Union => DataTypeKind::Union, - AdtKind::Enum => DataTypeKind::Enum, - } - } -} - -bitflags! { - #[derive(RustcEncodable, RustcDecodable, Default, HashStable)] - pub struct ReprFlags: u8 { - const IS_C = 1 << 0; - const IS_SIMD = 1 << 1; - const IS_TRANSPARENT = 1 << 2; - // Internal only for now. If true, don't reorder fields. - const IS_LINEAR = 1 << 3; - // If true, don't expose any niche to type's context. - const HIDE_NICHE = 1 << 4; - // Any of these flags being set prevent field reordering optimisation. - const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits | - ReprFlags::IS_SIMD.bits | - ReprFlags::IS_LINEAR.bits; - } -} - -/// Represents the repr options provided by the user, -#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Default, HashStable)] -pub struct ReprOptions { - pub int: Option<attr::IntType>, - pub align: Option<Align>, - pub pack: Option<Align>, - pub flags: ReprFlags, -} - -impl ReprOptions { - pub fn new(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions { - let mut flags = ReprFlags::empty(); - let mut size = None; - let mut max_align: Option<Align> = None; - let mut min_pack: Option<Align> = None; - for attr in tcx.get_attrs(did).iter() { - for r in attr::find_repr_attrs(&tcx.sess.parse_sess, attr) { - flags.insert(match r { - attr::ReprC => ReprFlags::IS_C, - attr::ReprPacked(pack) => { - let pack = Align::from_bytes(pack as u64).unwrap(); - min_pack = Some(if let Some(min_pack) = min_pack { - min_pack.min(pack) - } else { - pack - }); - ReprFlags::empty() - } - attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, - attr::ReprNoNiche => ReprFlags::HIDE_NICHE, - attr::ReprSimd => ReprFlags::IS_SIMD, - attr::ReprInt(i) => { - size = Some(i); - ReprFlags::empty() - } - attr::ReprAlign(align) => { - max_align = max_align.max(Some(Align::from_bytes(align as u64).unwrap())); - ReprFlags::empty() - } - }); - } - } - - // This is here instead of layout because the choice must make it into metadata. - if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.def_path_str(did))) { - flags.insert(ReprFlags::IS_LINEAR); - } - ReprOptions { int: size, align: max_align, pack: min_pack, flags: flags } - } - - #[inline] - pub fn simd(&self) -> bool { - self.flags.contains(ReprFlags::IS_SIMD) - } - #[inline] - pub fn c(&self) -> bool { - self.flags.contains(ReprFlags::IS_C) - } - #[inline] - pub fn packed(&self) -> bool { - self.pack.is_some() - } - #[inline] - pub fn transparent(&self) -> bool { - self.flags.contains(ReprFlags::IS_TRANSPARENT) - } - #[inline] - pub fn linear(&self) -> bool { - self.flags.contains(ReprFlags::IS_LINEAR) - } - #[inline] - pub fn hide_niche(&self) -> bool { - self.flags.contains(ReprFlags::HIDE_NICHE) - } - - pub fn discr_type(&self) -> attr::IntType { - self.int.unwrap_or(attr::SignedInt(ast::IntTy::Isize)) - } - - /// Returns `true` if this `#[repr()]` should inhabit "smart enum - /// layout" optimizations, such as representing `Foo<&T>` as a - /// single pointer. - pub fn inhibit_enum_layout_opt(&self) -> bool { - self.c() || self.int.is_some() - } - - /// Returns `true` if this `#[repr()]` should inhibit struct field reordering - /// optimizations, such as with `repr(C)`, `repr(packed(1))`, or `repr(<int>)`. - pub fn inhibit_struct_field_reordering_opt(&self) -> bool { - if let Some(pack) = self.pack { - if pack.bytes() == 1 { - return true; - } - } - self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some() - } - - /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations. - pub fn inhibit_union_abi_opt(&self) -> bool { - self.c() - } -} - -impl<'tcx> AdtDef { - /// Creates a new `AdtDef`. - fn new( - tcx: TyCtxt<'_>, - did: DefId, - kind: AdtKind, - variants: IndexVec<VariantIdx, VariantDef>, - repr: ReprOptions, - ) -> Self { - debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr); - let mut flags = AdtFlags::NO_ADT_FLAGS; - - if kind == AdtKind::Enum && tcx.has_attr(did, sym::non_exhaustive) { - debug!("found non-exhaustive variant list for {:?}", did); - flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE; - } - - flags |= match kind { - AdtKind::Enum => AdtFlags::IS_ENUM, - AdtKind::Union => AdtFlags::IS_UNION, - AdtKind::Struct => AdtFlags::IS_STRUCT, - }; - - if kind == AdtKind::Struct && variants[VariantIdx::new(0)].ctor_def_id.is_some() { - flags |= AdtFlags::HAS_CTOR; - } - - let attrs = tcx.get_attrs(did); - if attr::contains_name(&attrs, sym::fundamental) { - flags |= AdtFlags::IS_FUNDAMENTAL; - } - if Some(did) == tcx.lang_items().phantom_data() { - flags |= AdtFlags::IS_PHANTOM_DATA; - } - if Some(did) == tcx.lang_items().owned_box() { - flags |= AdtFlags::IS_BOX; - } - if Some(did) == tcx.lang_items().manually_drop() { - flags |= AdtFlags::IS_MANUALLY_DROP; - } - if Some(did) == tcx.lang_items().arc() { - flags |= AdtFlags::IS_ARC; - } - if Some(did) == tcx.lang_items().rc() { - flags |= AdtFlags::IS_RC; - } - - AdtDef { did, variants, flags, repr } - } - - /// Returns `true` if this is a struct. - #[inline] - pub fn is_struct(&self) -> bool { - self.flags.contains(AdtFlags::IS_STRUCT) - } - - /// Returns `true` if this is a union. - #[inline] - pub fn is_union(&self) -> bool { - self.flags.contains(AdtFlags::IS_UNION) - } - - /// Returns `true` if this is a enum. - #[inline] - pub fn is_enum(&self) -> bool { - self.flags.contains(AdtFlags::IS_ENUM) - } - - /// Returns `true` if the variant list of this ADT is `#[non_exhaustive]`. - #[inline] - pub fn is_variant_list_non_exhaustive(&self) -> bool { - self.flags.contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE) - } - - /// Returns the kind of the ADT. - #[inline] - pub fn adt_kind(&self) -> AdtKind { - if self.is_enum() { - AdtKind::Enum - } else if self.is_union() { - AdtKind::Union - } else { - AdtKind::Struct - } - } - - /// Returns a description of this abstract data type. - pub fn descr(&self) -> &'static str { - match self.adt_kind() { - AdtKind::Struct => "struct", - AdtKind::Union => "union", - AdtKind::Enum => "enum", - } - } - - /// Returns a description of a variant of this abstract data type. - #[inline] - pub fn variant_descr(&self) -> &'static str { - match self.adt_kind() { - AdtKind::Struct => "struct", - AdtKind::Union => "union", - AdtKind::Enum => "variant", - } - } - - /// If this function returns `true`, it implies that `is_struct` must return `true`. - #[inline] - pub fn has_ctor(&self) -> bool { - self.flags.contains(AdtFlags::HAS_CTOR) - } - - /// Returns `true` if this type is `#[fundamental]` for the purposes - /// of coherence checking. - #[inline] - pub fn is_fundamental(&self) -> bool { - self.flags.contains(AdtFlags::IS_FUNDAMENTAL) - } - - /// Returns `true` if this is `PhantomData<T>`. - #[inline] - pub fn is_phantom_data(&self) -> bool { - self.flags.contains(AdtFlags::IS_PHANTOM_DATA) - } - - /// Returns `true` if this is `Arc<T>`. - pub fn is_arc(&self) -> bool { - self.flags.contains(AdtFlags::IS_ARC) - } - - /// Returns `true` if this is `Rc<T>`. - pub fn is_rc(&self) -> bool { - self.flags.contains(AdtFlags::IS_RC) - } - - /// Returns `true` if this is Box<T>. - #[inline] - pub fn is_box(&self) -> bool { - self.flags.contains(AdtFlags::IS_BOX) - } - - /// Returns `true` if this is `ManuallyDrop<T>`. - #[inline] - pub fn is_manually_drop(&self) -> bool { - self.flags.contains(AdtFlags::IS_MANUALLY_DROP) - } - - /// Returns `true` if this type has a destructor. - pub fn has_dtor(&self, tcx: TyCtxt<'tcx>) -> bool { - self.destructor(tcx).is_some() - } - - /// Asserts this is a struct or union and returns its unique variant. - pub fn non_enum_variant(&self) -> &VariantDef { - assert!(self.is_struct() || self.is_union()); - &self.variants[VariantIdx::new(0)] - } - - #[inline] - pub fn predicates(&self, tcx: TyCtxt<'tcx>) -> GenericPredicates<'tcx> { - tcx.predicates_of(self.did) - } - - /// Returns an iterator over all fields contained - /// by this ADT. - #[inline] - pub fn all_fields(&self) -> impl Iterator<Item = &FieldDef> + Clone { - self.variants.iter().flat_map(|v| v.fields.iter()) - } - - pub fn is_payloadfree(&self) -> bool { - !self.variants.is_empty() && self.variants.iter().all(|v| v.fields.is_empty()) - } - - /// Return a `VariantDef` given a variant id. - pub fn variant_with_id(&self, vid: DefId) -> &VariantDef { - self.variants.iter().find(|v| v.def_id == vid).expect("variant_with_id: unknown variant") - } - - /// Return a `VariantDef` given a constructor id. - pub fn variant_with_ctor_id(&self, cid: DefId) -> &VariantDef { - self.variants - .iter() - .find(|v| v.ctor_def_id == Some(cid)) - .expect("variant_with_ctor_id: unknown variant") - } - - /// Return the index of `VariantDef` given a variant id. - pub fn variant_index_with_id(&self, vid: DefId) -> VariantIdx { - self.variants - .iter_enumerated() - .find(|(_, v)| v.def_id == vid) - .expect("variant_index_with_id: unknown variant") - .0 - } - - /// Return the index of `VariantDef` given a constructor id. - pub fn variant_index_with_ctor_id(&self, cid: DefId) -> VariantIdx { - self.variants - .iter_enumerated() - .find(|(_, v)| v.ctor_def_id == Some(cid)) - .expect("variant_index_with_ctor_id: unknown variant") - .0 - } - - pub fn variant_of_res(&self, res: Res) -> &VariantDef { - match res { - Res::Def(DefKind::Variant, vid) => self.variant_with_id(vid), - Res::Def(DefKind::Ctor(..), cid) => self.variant_with_ctor_id(cid), - Res::Def(DefKind::Struct, _) - | Res::Def(DefKind::Union, _) - | Res::Def(DefKind::TyAlias, _) - | Res::Def(DefKind::AssocTy, _) - | Res::SelfTy(..) - | Res::SelfCtor(..) => self.non_enum_variant(), - _ => bug!("unexpected res {:?} in variant_of_res", res), - } - } - - #[inline] - pub fn eval_explicit_discr(&self, tcx: TyCtxt<'tcx>, expr_did: DefId) -> Option<Discr<'tcx>> { - let param_env = tcx.param_env(expr_did); - let repr_type = self.repr.discr_type(); - match tcx.const_eval_poly(expr_did) { - Ok(val) => { - let ty = repr_type.to_ty(tcx); - if let Some(b) = val.try_to_bits_for_ty(tcx, param_env, ty) { - trace!("discriminants: {} ({:?})", b, repr_type); - Some(Discr { val: b, ty }) - } else { - info!("invalid enum discriminant: {:#?}", val); - crate::mir::interpret::struct_error( - tcx.at(tcx.def_span(expr_did)), - "constant evaluation of enum discriminant resulted in non-integer", - ) - .emit(); - None - } - } - Err(ErrorHandled::Reported) => { - if !expr_did.is_local() { - span_bug!( - tcx.def_span(expr_did), - "variant discriminant evaluation succeeded \ - in its crate but failed locally" - ); - } - None - } - Err(ErrorHandled::TooGeneric) => { - span_bug!(tcx.def_span(expr_did), "enum discriminant depends on generic arguments",) - } - } - } - - #[inline] - pub fn discriminants( - &'tcx self, - tcx: TyCtxt<'tcx>, - ) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> + Captures<'tcx> { - let repr_type = self.repr.discr_type(); - let initial = repr_type.initial_discriminant(tcx); - let mut prev_discr = None::<Discr<'tcx>>; - self.variants.iter_enumerated().map(move |(i, v)| { - let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx)); - if let VariantDiscr::Explicit(expr_did) = v.discr { - if let Some(new_discr) = self.eval_explicit_discr(tcx, expr_did) { - discr = new_discr; - } - } - prev_discr = Some(discr); - - (i, discr) - }) - } - - #[inline] - pub fn variant_range(&self) -> Range<VariantIdx> { - VariantIdx::new(0)..VariantIdx::new(self.variants.len()) - } - - /// Computes the discriminant value used by a specific variant. - /// Unlike `discriminants`, this is (amortized) constant-time, - /// only doing at most one query for evaluating an explicit - /// discriminant (the last one before the requested variant), - /// assuming there are no constant-evaluation errors there. - #[inline] - pub fn discriminant_for_variant( - &self, - tcx: TyCtxt<'tcx>, - variant_index: VariantIdx, - ) -> Discr<'tcx> { - let (val, offset) = self.discriminant_def_for_variant(variant_index); - let explicit_value = val - .and_then(|expr_did| self.eval_explicit_discr(tcx, expr_did)) - .unwrap_or_else(|| self.repr.discr_type().initial_discriminant(tcx)); - explicit_value.checked_add(tcx, offset as u128).0 - } - - /// Yields a `DefId` for the discriminant and an offset to add to it - /// Alternatively, if there is no explicit discriminant, returns the - /// inferred discriminant directly. - pub fn discriminant_def_for_variant(&self, variant_index: VariantIdx) -> (Option<DefId>, u32) { - let mut explicit_index = variant_index.as_u32(); - let expr_did; - loop { - match self.variants[VariantIdx::from_u32(explicit_index)].discr { - ty::VariantDiscr::Relative(0) => { - expr_did = None; - break; - } - ty::VariantDiscr::Relative(distance) => { - explicit_index -= distance; - } - ty::VariantDiscr::Explicit(did) => { - expr_did = Some(did); - break; - } - } - } - (expr_did, variant_index.as_u32() - explicit_index) - } - - pub fn destructor(&self, tcx: TyCtxt<'tcx>) -> Option<Destructor> { - tcx.adt_destructor(self.did) - } - - /// Returns a list of types such that `Self: Sized` if and only - /// if that type is `Sized`, or `TyErr` if this type is recursive. - /// - /// Oddly enough, checking that the sized-constraint is `Sized` is - /// actually more expressive than checking all members: - /// the `Sized` trait is inductive, so an associated type that references - /// `Self` would prevent its containing ADT from being `Sized`. - /// - /// Due to normalization being eager, this applies even if - /// the associated type is behind a pointer (e.g., issue #31299). - pub fn sized_constraint(&self, tcx: TyCtxt<'tcx>) -> &'tcx [Ty<'tcx>] { - tcx.adt_sized_constraint(self.did).0 - } -} - -impl<'tcx> FieldDef { - /// Returns the type of this field. The `subst` is typically obtained - /// via the second field of `TyKind::AdtDef`. - pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> { - tcx.type_of(self.did).subst(tcx, subst) - } -} - -/// Represents the various closure traits in the language. This -/// will determine the type of the environment (`self`, in the -/// desugaring) argument that the closure expects. -/// -/// You can get the environment type of a closure using -/// `tcx.closure_env_ty()`. -#[derive( - Clone, - Copy, - PartialOrd, - Ord, - PartialEq, - Eq, - Hash, - Debug, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub enum ClosureKind { - // Warning: Ordering is significant here! The ordering is chosen - // because the trait Fn is a subtrait of FnMut and so in turn, and - // hence we order it so that Fn < FnMut < FnOnce. - Fn, - FnMut, - FnOnce, -} - -impl<'tcx> ClosureKind { - // This is the initial value used when doing upvar inference. - pub const LATTICE_BOTTOM: ClosureKind = ClosureKind::Fn; - - pub fn trait_did(&self, tcx: TyCtxt<'tcx>) -> DefId { - match *self { - ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem, None), - ClosureKind::FnMut => tcx.require_lang_item(FnMutTraitLangItem, None), - ClosureKind::FnOnce => tcx.require_lang_item(FnOnceTraitLangItem, None), - } - } - - /// Returns `true` if this a type that impls this closure kind - /// must also implement `other`. - pub fn extends(self, other: ty::ClosureKind) -> bool { - match (self, other) { - (ClosureKind::Fn, ClosureKind::Fn) => true, - (ClosureKind::Fn, ClosureKind::FnMut) => true, - (ClosureKind::Fn, ClosureKind::FnOnce) => true, - (ClosureKind::FnMut, ClosureKind::FnMut) => true, - (ClosureKind::FnMut, ClosureKind::FnOnce) => true, - (ClosureKind::FnOnce, ClosureKind::FnOnce) => true, - _ => false, - } - } - - /// Returns the representative scalar type for this closure kind. - /// See `TyS::to_opt_closure_kind` for more details. - pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self { - ty::ClosureKind::Fn => tcx.types.i8, - ty::ClosureKind::FnMut => tcx.types.i16, - ty::ClosureKind::FnOnce => tcx.types.i32, - } - } -} - -impl<'tcx> TyS<'tcx> { - /// Iterator that walks `self` and any types reachable from - /// `self`, in depth-first order. Note that just walks the types - /// that appear in `self`, it does not descend into the fields of - /// structs or variants. For example: - /// - /// ```notrust - /// isize => { isize } - /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize } - /// [isize] => { [isize], isize } - /// ``` - pub fn walk(&'tcx self) -> TypeWalker<'tcx> { - TypeWalker::new(self) - } - - /// Iterator that walks the immediate children of `self`. Hence - /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]` - /// (but not `i32`, like `walk`). - pub fn walk_shallow(&'tcx self) -> smallvec::IntoIter<walk::TypeWalkerArray<'tcx>> { - walk::walk_shallow(self) - } - - /// Walks `ty` and any types appearing within `ty`, invoking the - /// callback `f` on each type. If the callback returns `false`, then the - /// children of the current type are ignored. - /// - /// Note: prefer `ty.walk()` where possible. - pub fn maybe_walk<F>(&'tcx self, mut f: F) - where - F: FnMut(Ty<'tcx>) -> bool, - { - let mut walker = self.walk(); - while let Some(ty) = walker.next() { - if !f(ty) { - walker.skip_current_subtree(); - } - } - } -} - -impl BorrowKind { - pub fn from_mutbl(m: hir::Mutability) -> BorrowKind { - match m { - hir::Mutability::Mut => MutBorrow, - hir::Mutability::Not => ImmBorrow, - } - } - - /// Returns a mutability `m` such that an `&m T` pointer could be used to obtain this borrow - /// kind. Because borrow kinds are richer than mutabilities, we sometimes have to pick a - /// mutability that is stronger than necessary so that it at least *would permit* the borrow in - /// question. - pub fn to_mutbl_lossy(self) -> hir::Mutability { - match self { - MutBorrow => hir::Mutability::Mut, - ImmBorrow => hir::Mutability::Not, - - // We have no type corresponding to a unique imm borrow, so - // use `&mut`. It gives all the capabilities of an `&uniq` - // and hence is a safe "over approximation". - UniqueImmBorrow => hir::Mutability::Mut, - } - } - - pub fn to_user_str(&self) -> &'static str { - match *self { - MutBorrow => "mutable", - ImmBorrow => "immutable", - UniqueImmBorrow => "uniquely immutable", - } - } -} - -#[derive(Debug, Clone)] -pub enum Attributes<'tcx> { - Owned(Lrc<[ast::Attribute]>), - Borrowed(&'tcx [ast::Attribute]), -} - -impl<'tcx> ::std::ops::Deref for Attributes<'tcx> { - type Target = [ast::Attribute]; - - fn deref(&self) -> &[ast::Attribute] { - match self { - &Attributes::Owned(ref data) => &data, - &Attributes::Borrowed(data) => data, - } - } -} - -#[derive(Debug, PartialEq, Eq)] -pub enum ImplOverlapKind { - /// These impls are always allowed to overlap. - Permitted { - /// Whether or not the impl is permitted due to the trait being a `#[marker]` trait - marker: bool, - }, - /// These impls are allowed to overlap, but that raises - /// an issue #33140 future-compatibility warning. - /// - /// Some background: in Rust 1.0, the trait-object types `Send + Sync` (today's - /// `dyn Send + Sync`) and `Sync + Send` (now `dyn Sync + Send`) were different. - /// - /// The widely-used version 0.1.0 of the crate `traitobject` had accidentally relied - /// that difference, making what reduces to the following set of impls: - /// - /// ``` - /// trait Trait {} - /// impl Trait for dyn Send + Sync {} - /// impl Trait for dyn Sync + Send {} - /// ``` - /// - /// Obviously, once we made these types be identical, that code causes a coherence - /// error and a fairly big headache for us. However, luckily for us, the trait - /// `Trait` used in this case is basically a marker trait, and therefore having - /// overlapping impls for it is sound. - /// - /// To handle this, we basically regard the trait as a marker trait, with an additional - /// future-compatibility warning. To avoid accidentally "stabilizing" this feature, - /// it has the following restrictions: - /// - /// 1. The trait must indeed be a marker-like trait (i.e., no items), and must be - /// positive impls. - /// 2. The trait-ref of both impls must be equal. - /// 3. The trait-ref of both impls must be a trait object type consisting only of - /// marker traits. - /// 4. Neither of the impls can have any where-clauses. - /// - /// Once `traitobject` 0.1.0 is no longer an active concern, this hack can be removed. - Issue33140, -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn body_tables(self, body: hir::BodyId) -> &'tcx TypeckTables<'tcx> { - self.typeck_tables_of(self.hir().body_owner_def_id(body)) - } - - /// Returns an iterator of the `DefId`s for all body-owners in this - /// crate. If you would prefer to iterate over the bodies - /// themselves, you can do `self.hir().krate().body_ids.iter()`. - pub fn body_owners(self) -> impl Iterator<Item = DefId> + Captures<'tcx> + 'tcx { - self.hir() - .krate() - .body_ids - .iter() - .map(move |&body_id| self.hir().body_owner_def_id(body_id)) - } - - pub fn par_body_owners<F: Fn(DefId) + sync::Sync + sync::Send>(self, f: F) { - par_iter(&self.hir().krate().body_ids) - .for_each(|&body_id| f(self.hir().body_owner_def_id(body_id))); - } - - pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> { - self.associated_items(id) - .in_definition_order() - .filter(|item| item.kind == AssocKind::Method && item.defaultness.has_value()) - } - - pub fn trait_relevant_for_never(self, did: DefId) -> bool { - self.associated_items(did).in_definition_order().any(|item| item.relevant_for_never()) - } - - pub fn opt_item_name(self, def_id: DefId) -> Option<Ident> { - self.hir().as_local_hir_id(def_id).and_then(|hir_id| self.hir().get(hir_id).ident()) - } - - pub fn opt_associated_item(self, def_id: DefId) -> Option<AssocItem> { - let is_associated_item = if let Some(hir_id) = self.hir().as_local_hir_id(def_id) { - match self.hir().get(hir_id) { - Node::TraitItem(_) | Node::ImplItem(_) => true, - _ => false, - } - } else { - match self.def_kind(def_id).expect("no def for `DefId`") { - DefKind::AssocConst | DefKind::Method | DefKind::AssocTy => true, - _ => false, - } - }; - - is_associated_item.then(|| self.associated_item(def_id)) - } - - pub fn field_index(self, hir_id: hir::HirId, tables: &TypeckTables<'_>) -> usize { - tables.field_indices().get(hir_id).cloned().expect("no index for a field") - } - - pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<usize> { - variant.fields.iter().position(|field| self.hygienic_eq(ident, field.ident, variant.def_id)) - } - - /// Returns `true` if the impls are the same polarity and the trait either - /// has no items or is annotated #[marker] and prevents item overrides. - pub fn impls_are_allowed_to_overlap( - self, - def_id1: DefId, - def_id2: DefId, - ) -> Option<ImplOverlapKind> { - // If either trait impl references an error, they're allowed to overlap, - // as one of them essentially doesn't exist. - if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.references_error()) - || self.impl_trait_ref(def_id2).map_or(false, |tr| tr.references_error()) - { - return Some(ImplOverlapKind::Permitted { marker: false }); - } - - match (self.impl_polarity(def_id1), self.impl_polarity(def_id2)) { - (ImplPolarity::Reservation, _) | (_, ImplPolarity::Reservation) => { - // `#[rustc_reservation_impl]` impls don't overlap with anything - debug!( - "impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (reservations)", - def_id1, def_id2 - ); - return Some(ImplOverlapKind::Permitted { marker: false }); - } - (ImplPolarity::Positive, ImplPolarity::Negative) - | (ImplPolarity::Negative, ImplPolarity::Positive) => { - // `impl AutoTrait for Type` + `impl !AutoTrait for Type` - debug!( - "impls_are_allowed_to_overlap({:?}, {:?}) - None (differing polarities)", - def_id1, def_id2 - ); - return None; - } - (ImplPolarity::Positive, ImplPolarity::Positive) - | (ImplPolarity::Negative, ImplPolarity::Negative) => {} - }; - - let is_marker_overlap = { - let is_marker_impl = |def_id: DefId| -> bool { - let trait_ref = self.impl_trait_ref(def_id); - trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker) - }; - is_marker_impl(def_id1) && is_marker_impl(def_id2) - }; - - if is_marker_overlap { - debug!( - "impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (marker overlap)", - def_id1, def_id2 - ); - Some(ImplOverlapKind::Permitted { marker: true }) - } else { - if let Some(self_ty1) = self.issue33140_self_ty(def_id1) { - if let Some(self_ty2) = self.issue33140_self_ty(def_id2) { - if self_ty1 == self_ty2 { - debug!( - "impls_are_allowed_to_overlap({:?}, {:?}) - issue #33140 HACK", - def_id1, def_id2 - ); - return Some(ImplOverlapKind::Issue33140); - } else { - debug!( - "impls_are_allowed_to_overlap({:?}, {:?}) - found {:?} != {:?}", - def_id1, def_id2, self_ty1, self_ty2 - ); - } - } - } - - debug!("impls_are_allowed_to_overlap({:?}, {:?}) = None", def_id1, def_id2); - None - } - } - - /// Returns `ty::VariantDef` if `res` refers to a struct, - /// or variant or their constructors, panics otherwise. - pub fn expect_variant_res(self, res: Res) -> &'tcx VariantDef { - match res { - Res::Def(DefKind::Variant, did) => { - let enum_did = self.parent(did).unwrap(); - self.adt_def(enum_did).variant_with_id(did) - } - Res::Def(DefKind::Struct, did) | Res::Def(DefKind::Union, did) => { - self.adt_def(did).non_enum_variant() - } - Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_did) => { - let variant_did = self.parent(variant_ctor_did).unwrap(); - let enum_did = self.parent(variant_did).unwrap(); - self.adt_def(enum_did).variant_with_ctor_id(variant_ctor_did) - } - Res::Def(DefKind::Ctor(CtorOf::Struct, ..), ctor_did) => { - let struct_did = self.parent(ctor_did).expect("struct ctor has no parent"); - self.adt_def(struct_did).non_enum_variant() - } - _ => bug!("expect_variant_res used with unexpected res {:?}", res), - } - } - - pub fn item_name(self, id: DefId) -> Symbol { - if id.index == CRATE_DEF_INDEX { - self.original_crate_name(id.krate) - } else { - let def_key = self.def_key(id); - match def_key.disambiguated_data.data { - // The name of a constructor is that of its parent. - hir_map::DefPathData::Ctor => { - self.item_name(DefId { krate: id.krate, index: def_key.parent.unwrap() }) - } - _ => def_key.disambiguated_data.data.get_opt_name().unwrap_or_else(|| { - bug!("item_name: no name for {:?}", self.def_path(id)); - }), - } - } - } - - /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair. - pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> ReadOnlyBodyAndCache<'tcx, 'tcx> { - match instance { - ty::InstanceDef::Item(did) => self.optimized_mir(did).unwrap_read_only(), - ty::InstanceDef::VtableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::Intrinsic(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::CloneShim(..) => self.mir_shims(instance).unwrap_read_only(), - } - } - - /// Gets the attributes of a definition. - pub fn get_attrs(self, did: DefId) -> Attributes<'tcx> { - if let Some(id) = self.hir().as_local_hir_id(did) { - Attributes::Borrowed(self.hir().attrs(id)) - } else { - Attributes::Owned(self.item_attrs(did)) - } - } - - /// Determines whether an item is annotated with an attribute. - pub fn has_attr(self, did: DefId, attr: Symbol) -> bool { - attr::contains_name(&self.get_attrs(did), attr) - } - - /// Returns `true` if this is an `auto trait`. - pub fn trait_is_auto(self, trait_def_id: DefId) -> bool { - self.trait_def(trait_def_id).has_auto_impl - } - - pub fn generator_layout(self, def_id: DefId) -> &'tcx GeneratorLayout<'tcx> { - self.optimized_mir(def_id).generator_layout.as_ref().unwrap() - } - - /// Given the `DefId` of an impl, returns the `DefId` of the trait it implements. - /// If it implements no trait, returns `None`. - pub fn trait_id_of_impl(self, def_id: DefId) -> Option<DefId> { - self.impl_trait_ref(def_id).map(|tr| tr.def_id) - } - - /// If the given defid describes a method belonging to an impl, returns the - /// `DefId` of the impl that the method belongs to; otherwise, returns `None`. - pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> { - let item = if def_id.krate != LOCAL_CRATE { - if let Some(DefKind::Method) = self.def_kind(def_id) { - Some(self.associated_item(def_id)) - } else { - None - } - } else { - self.opt_associated_item(def_id) - }; - - item.and_then(|trait_item| match trait_item.container { - TraitContainer(_) => None, - ImplContainer(def_id) => Some(def_id), - }) - } - - /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` - /// with the name of the crate containing the impl. - pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> { - if impl_did.is_local() { - let hir_id = self.hir().as_local_hir_id(impl_did).unwrap(); - Ok(self.hir().span(hir_id)) - } else { - Err(self.crate_name(impl_did.krate)) - } - } - - /// Hygienically compares a use-site name (`use_name`) for a field or an associated item with - /// its supposed definition name (`def_name`). The method also needs `DefId` of the supposed - /// definition's parent/scope to perform comparison. - pub fn hygienic_eq(self, use_name: Ident, def_name: Ident, def_parent_def_id: DefId) -> bool { - // We could use `Ident::eq` here, but we deliberately don't. The name - // comparison fails frequently, and we want to avoid the expensive - // `modern()` calls required for the span comparison whenever possible. - use_name.name == def_name.name - && use_name - .span - .ctxt() - .hygienic_eq(def_name.span.ctxt(), self.expansion_that_defined(def_parent_def_id)) - } - - fn expansion_that_defined(self, scope: DefId) -> ExpnId { - match scope.krate { - LOCAL_CRATE => self.hir().definitions().expansion_that_defined(scope.index), - _ => ExpnId::root(), - } - } - - pub fn adjust_ident(self, mut ident: Ident, scope: DefId) -> Ident { - ident.span.modernize_and_adjust(self.expansion_that_defined(scope)); - ident - } - - pub fn adjust_ident_and_get_scope( - self, - mut ident: Ident, - scope: DefId, - block: hir::HirId, - ) -> (Ident, DefId) { - let scope = match ident.span.modernize_and_adjust(self.expansion_that_defined(scope)) { - Some(actual_expansion) => { - self.hir().definitions().parent_module_of_macro_def(actual_expansion) - } - None => self.hir().get_module_parent(block), - }; - (ident, scope) - } - - pub fn is_object_safe(self, key: DefId) -> bool { - self.object_safety_violations(key).is_empty() - } -} - -#[derive(Clone, HashStable)] -pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]); - -/// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition. -pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> { - if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { - if let Node::Item(item) = tcx.hir().get(hir_id) { - if let hir::ItemKind::OpaqueTy(ref opaque_ty) = item.kind { - return opaque_ty.impl_trait_fn; - } - } - } - None -} - -pub fn provide(providers: &mut ty::query::Providers<'_>) { - context::provide(providers); - erase_regions::provide(providers); - layout::provide(providers); - *providers = - ty::query::Providers { trait_impls_of: trait_def::trait_impls_of_provider, ..*providers }; -} - -/// A map for the local crate mapping each type to a vector of its -/// inherent impls. This is not meant to be used outside of coherence; -/// rather, you should request the vector for a specific type via -/// `tcx.inherent_impls(def_id)` so as to minimize your dependencies -/// (constructing this map requires touching the entire crate). -#[derive(Clone, Debug, Default, HashStable)] -pub struct CrateInherentImpls { - pub inherent_impls: DefIdMap<Vec<DefId>>, -} - -#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] -pub struct SymbolName { - // FIXME: we don't rely on interning or equality here - better have - // this be a `&'tcx str`. - pub name: Symbol, -} - -impl SymbolName { - pub fn new(name: &str) -> SymbolName { - SymbolName { name: Symbol::intern(name) } - } -} - -impl PartialOrd for SymbolName { - fn partial_cmp(&self, other: &SymbolName) -> Option<Ordering> { - self.name.as_str().partial_cmp(&other.name.as_str()) - } -} - -/// Ordering must use the chars to ensure reproducible builds. -impl Ord for SymbolName { - fn cmp(&self, other: &SymbolName) -> Ordering { - self.name.as_str().cmp(&other.name.as_str()) - } -} - -impl fmt::Display for SymbolName { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.name, fmt) - } -} - -impl fmt::Debug for SymbolName { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.name, fmt) - } -} diff --git a/src/librustc/ty/normalize_erasing_regions.rs b/src/librustc/ty/normalize_erasing_regions.rs deleted file mode 100644 index dc64482907f..00000000000 --- a/src/librustc/ty/normalize_erasing_regions.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! Methods for normalizing when you don't care about regions (and -//! aren't doing type inference). If either of those things don't -//! apply to you, use `infcx.normalize(...)`. -//! -//! The methods in this file use a `TypeFolder` to recursively process -//! contents, invoking the underlying -//! `normalize_ty_after_erasing_regions` query for each type found -//! within. (This underlying query is what is cached.) - -use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::subst::{Subst, SubstsRef}; -use crate::ty::{self, Ty, TyCtxt}; - -impl<'tcx> TyCtxt<'tcx> { - /// Erase the regions in `value` and then fully normalize all the - /// types found within. The result will also have regions erased. - /// - /// This is appropriate to use only after type-check: it assumes - /// that normalization will succeed, for example. - pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T - where - T: TypeFoldable<'tcx>, - { - debug!( - "normalize_erasing_regions::<{}>(value={:?}, param_env={:?})", - ::std::any::type_name::<T>(), - value, - param_env, - ); - - // Erase first before we do the real query -- this keeps the - // cache from being too polluted. - let value = self.erase_regions(&value); - if !value.has_projections() { - value - } else { - value.fold_with(&mut NormalizeAfterErasingRegionsFolder { - tcx: self, - param_env: param_env, - }) - } - } - - /// If you have a `Binder<T>`, you can do this to strip out the - /// late-bound regions and then normalize the result, yielding up - /// a `T` (with regions erased). This is appropriate when the - /// binder is being instantiated at the call site. - /// - /// N.B., currently, higher-ranked type bounds inhibit - /// normalization. Therefore, each time we erase them in - /// codegen, we need to normalize the contents. - pub fn normalize_erasing_late_bound_regions<T>( - self, - param_env: ty::ParamEnv<'tcx>, - value: &ty::Binder<T>, - ) -> T - where - T: TypeFoldable<'tcx>, - { - assert!(!value.needs_subst()); - let value = self.erase_late_bound_regions(value); - self.normalize_erasing_regions(param_env, value) - } - - /// Monomorphizes a type from the AST by first applying the - /// in-scope substitutions and then normalizing any associated - /// types. - pub fn subst_and_normalize_erasing_regions<T>( - self, - param_substs: SubstsRef<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - debug!( - "subst_and_normalize_erasing_regions(\ - param_substs={:?}, \ - value={:?}, \ - param_env={:?})", - param_substs, value, param_env, - ); - let substituted = value.subst(self, param_substs); - self.normalize_erasing_regions(param_env, substituted) - } -} - -struct NormalizeAfterErasingRegionsFolder<'tcx> { - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, -} - -impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.tcx.normalize_ty_after_erasing_regions(self.param_env.and(ty)) - } -} diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs deleted file mode 100644 index b397a2c80d5..00000000000 --- a/src/librustc/ty/outlives.rs +++ /dev/null @@ -1,178 +0,0 @@ -// The outlines relation `T: 'a` or `'a: 'b`. This code frequently -// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that -// RFC for reference. - -use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; -use smallvec::SmallVec; - -#[derive(Debug)] -pub enum Component<'tcx> { - Region(ty::Region<'tcx>), - Param(ty::ParamTy), - UnresolvedInferenceVariable(ty::InferTy), - - // Projections like `T::Foo` are tricky because a constraint like - // `T::Foo: 'a` can be satisfied in so many ways. There may be a - // where-clause that says `T::Foo: 'a`, or the defining trait may - // include a bound like `type Foo: 'static`, or -- in the most - // conservative way -- we can prove that `T: 'a` (more generally, - // that all components in the projection outlive `'a`). This code - // is not in a position to judge which is the best technique, so - // we just product the projection as a component and leave it to - // the consumer to decide (but see `EscapingProjection` below). - Projection(ty::ProjectionTy<'tcx>), - - // In the case where a projection has escaping regions -- meaning - // regions bound within the type itself -- we always use - // the most conservative rule, which requires that all components - // outlive the bound. So for example if we had a type like this: - // - // for<'a> Trait1< <T as Trait2<'a,'b>>::Foo > - // ~~~~~~~~~~~~~~~~~~~~~~~~~ - // - // then the inner projection (underlined) has an escaping region - // `'a`. We consider that outer trait `'c` to meet a bound if `'b` - // outlives `'b: 'c`, and we don't consider whether the trait - // declares that `Foo: 'static` etc. Therefore, we just return the - // free components of such a projection (in this case, `'b`). - // - // However, in the future, we may want to get smarter, and - // actually return a "higher-ranked projection" here. Therefore, - // we mark that these components are part of an escaping - // projection, so that implied bounds code can avoid relying on - // them. This gives us room to improve the regionck reasoning in - // the future without breaking backwards compat. - EscapingProjection(Vec<Component<'tcx>>), -} - -impl<'tcx> TyCtxt<'tcx> { - /// Push onto `out` all the things that must outlive `'a` for the condition - /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. - pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { - compute_components(self, ty0, out); - debug!("components({:?}) = {:?}", ty0, out); - } -} - -fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { - // Descend through the types, looking for the various "base" - // components and collecting them into `out`. This is not written - // with `collect()` because of the need to sometimes skip subtrees - // in the `subtys` iterator (e.g., when encountering a - // projection). - match ty.kind { - ty::Closure(def_id, ref substs) => { - for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) { - compute_components(tcx, upvar_ty, out); - } - } - - ty::Generator(def_id, ref substs, _) => { - // Same as the closure case - for upvar_ty in substs.as_generator().upvar_tys(def_id, tcx) { - compute_components(tcx, upvar_ty, out); - } - - // We ignore regions in the generator interior as we don't - // want these to affect region inference - } - - // All regions are bound inside a witness - ty::GeneratorWitness(..) => (), - - // OutlivesTypeParameterEnv -- the actual checking that `X:'a` - // is implied by the environment is done in regionck. - ty::Param(p) => { - out.push(Component::Param(p)); - } - - // For projections, we prefer to generate an obligation like - // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the - // regionck more ways to prove that it holds. However, - // regionck is not (at least currently) prepared to deal with - // higher-ranked regions that may appear in the - // trait-ref. Therefore, if we see any higher-ranke regions, - // we simply fallback to the most restrictive rule, which - // requires that `Pi: 'a` for all `i`. - ty::Projection(ref data) => { - if !data.has_escaping_bound_vars() { - // best case: no escaping regions, so push the - // projection and skip the subtree (thus generating no - // constraints for Pi). This defers the choice between - // the rules OutlivesProjectionEnv, - // OutlivesProjectionTraitDef, and - // OutlivesProjectionComponents to regionck. - out.push(Component::Projection(*data)); - } else { - // fallback case: hard code - // OutlivesProjectionComponents. Continue walking - // through and constrain Pi. - let subcomponents = capture_components(tcx, ty); - out.push(Component::EscapingProjection(subcomponents)); - } - } - - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - - // We assume that inference variables are fully resolved. - // So, if we encounter an inference variable, just record - // the unresolved variable as a component. - ty::Infer(infer_ty) => { - out.push(Component::UnresolvedInferenceVariable(infer_ty)); - } - - // Most types do not introduce any region binders, nor - // involve any other subtle cases, and so the WF relation - // simply constraints any regions referenced directly by - // the type and then visits the types that are lexically - // contained within. (The comments refer to relevant rules - // from RFC1214.) - ty::Bool | // OutlivesScalar - ty::Char | // OutlivesScalar - ty::Int(..) | // OutlivesScalar - ty::Uint(..) | // OutlivesScalar - ty::Float(..) | // OutlivesScalar - ty::Never | // ... - ty::Adt(..) | // OutlivesNominalType - ty::Opaque(..) | // OutlivesNominalType (ish) - ty::Foreign(..) | // OutlivesNominalType - ty::Str | // OutlivesScalar (ish) - ty::Array(..) | // ... - ty::Slice(..) | // ... - ty::RawPtr(..) | // ... - ty::Ref(..) | // OutlivesReference - ty::Tuple(..) | // ... - ty::FnDef(..) | // OutlivesFunction (*) - ty::FnPtr(_) | // OutlivesFunction (*) - ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) - ty::Placeholder(..) | - ty::Bound(..) | - ty::Error => { - // (*) Bare functions and traits are both binders. In the - // RFC, this means we would add the bound regions to the - // "bound regions list". In our representation, no such - // list is maintained explicitly, because bound regions - // themselves can be readily identified. - - push_region_constraints(ty, out); - for subty in ty.walk_shallow() { - compute_components(tcx, subty, out); - } - } - } -} - -fn capture_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec<Component<'tcx>> { - let mut temp = smallvec![]; - push_region_constraints(ty, &mut temp); - for subty in ty.walk_shallow() { - compute_components(tcx, subty, &mut temp); - } - temp.into_iter().collect() -} - -fn push_region_constraints<'tcx>(ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { - let mut regions = smallvec![]; - ty.push_regions(&mut regions); - out.extend(regions.iter().filter(|&r| !r.is_late_bound()).map(|r| Component::Region(r))); -} diff --git a/src/librustc/ty/print/mod.rs b/src/librustc/ty/print/mod.rs deleted file mode 100644 index 3ade9661917..00000000000 --- a/src/librustc/ty/print/mod.rs +++ /dev/null @@ -1,347 +0,0 @@ -use crate::hir::map::{DefPathData, DisambiguatedDefPathData}; -use crate::ty::subst::{GenericArg, Subst}; -use crate::ty::{self, DefIdTree, Ty, TyCtxt}; - -use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def_id::{CrateNum, DefId}; - -// `pretty` is a separate module only for organization. -mod pretty; -pub use self::pretty::*; - -pub mod obsolete; - -// FIXME(eddyb) false positive, the lifetime parameters are used with `P: Printer<...>`. -#[allow(unused_lifetimes)] -pub trait Print<'tcx, P> { - type Output; - type Error; - - fn print(&self, cx: P) -> Result<Self::Output, Self::Error>; -} - -/// Interface for outputting user-facing "type-system entities" -/// (paths, types, lifetimes, constants, etc.) as a side-effect -/// (e.g. formatting, like `PrettyPrinter` implementors do) or by -/// constructing some alternative representation (e.g. an AST), -/// which the associated types allow passing through the methods. -/// -/// For pretty-printing/formatting in particular, see `PrettyPrinter`. -// -// FIXME(eddyb) find a better name; this is more general than "printing". -pub trait Printer<'tcx>: Sized { - type Error; - - type Path; - type Region; - type Type; - type DynExistential; - type Const; - - fn tcx(&'a self) -> TyCtxt<'tcx>; - - fn print_def_path( - self, - def_id: DefId, - substs: &'tcx [GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { - self.default_print_def_path(def_id, substs) - } - - fn print_impl_path( - self, - impl_def_id: DefId, - substs: &'tcx [GenericArg<'tcx>], - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - self.default_print_impl_path(impl_def_id, substs, self_ty, trait_ref) - } - - fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error>; - - fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>; - - fn print_dyn_existential( - self, - predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error>; - - fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error>; - - fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error>; - - fn path_qualified( - self, - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error>; - - fn path_append_impl( - self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - disambiguated_data: &DisambiguatedDefPathData, - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error>; - - fn path_append( - self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error>; - - fn path_generic_args( - self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error>; - - // Defaults (should not be overriden): - - fn default_print_def_path( - self, - def_id: DefId, - substs: &'tcx [GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { - debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs); - let key = self.tcx().def_key(def_id); - debug!("default_print_def_path: key={:?}", key); - - match key.disambiguated_data.data { - DefPathData::CrateRoot => { - assert!(key.parent.is_none()); - self.path_crate(def_id.krate) - } - - DefPathData::Impl => { - let generics = self.tcx().generics_of(def_id); - let mut self_ty = self.tcx().type_of(def_id); - let mut impl_trait_ref = self.tcx().impl_trait_ref(def_id); - if substs.len() >= generics.count() { - self_ty = self_ty.subst(self.tcx(), substs); - impl_trait_ref = impl_trait_ref.subst(self.tcx(), substs); - } - self.print_impl_path(def_id, substs, self_ty, impl_trait_ref) - } - - _ => { - let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id }; - - let mut parent_substs = substs; - let mut trait_qualify_parent = false; - if !substs.is_empty() { - let generics = self.tcx().generics_of(def_id); - parent_substs = &substs[..generics.parent_count.min(substs.len())]; - - match key.disambiguated_data.data { - // Closures' own generics are only captures, don't print them. - DefPathData::ClosureExpr => {} - - // If we have any generic arguments to print, we do that - // on top of the same path, but without its own generics. - _ => { - if !generics.params.is_empty() && substs.len() >= generics.count() { - let args = self.generic_args_to_print(generics, substs); - return self.path_generic_args( - |cx| cx.print_def_path(def_id, parent_substs), - args, - ); - } - } - } - - // FIXME(eddyb) try to move this into the parent's printing - // logic, instead of doing it when printing the child. - trait_qualify_parent = generics.has_self - && generics.parent == Some(parent_def_id) - && parent_substs.len() == generics.parent_count - && self.tcx().generics_of(parent_def_id).parent_count == 0; - } - - self.path_append( - |cx: Self| { - if trait_qualify_parent { - let trait_ref = ty::TraitRef::new( - parent_def_id, - cx.tcx().intern_substs(parent_substs), - ); - cx.path_qualified(trait_ref.self_ty(), Some(trait_ref)) - } else { - cx.print_def_path(parent_def_id, parent_substs) - } - }, - &key.disambiguated_data, - ) - } - } - } - - fn generic_args_to_print( - &self, - generics: &'tcx ty::Generics, - substs: &'tcx [GenericArg<'tcx>], - ) -> &'tcx [GenericArg<'tcx>] { - let mut own_params = generics.parent_count..generics.count(); - - // Don't print args for `Self` parameters (of traits). - if generics.has_self && own_params.start == 0 { - own_params.start = 1; - } - - // Don't print args that are the defaults of their respective parameters. - own_params.end -= generics - .params - .iter() - .rev() - .take_while(|param| { - match param.kind { - ty::GenericParamDefKind::Lifetime => false, - ty::GenericParamDefKind::Type { has_default, .. } => { - has_default - && substs[param.index as usize] - == GenericArg::from( - self.tcx().type_of(param.def_id).subst(self.tcx(), substs), - ) - } - ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults) - } - }) - .count(); - - &substs[own_params] - } - - fn default_print_impl_path( - self, - impl_def_id: DefId, - _substs: &'tcx [GenericArg<'tcx>], - self_ty: Ty<'tcx>, - impl_trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - debug!( - "default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}", - impl_def_id, self_ty, impl_trait_ref - ); - - let key = self.tcx().def_key(impl_def_id); - let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id }; - - // Decide whether to print the parent path for the impl. - // Logically, since impls are global, it's never needed, but - // users may find it useful. Currently, we omit the parent if - // the impl is either in the same module as the self-type or - // as the trait. - let in_self_mod = match characteristic_def_id_of_type(self_ty) { - None => false, - Some(ty_def_id) => self.tcx().parent(ty_def_id) == Some(parent_def_id), - }; - let in_trait_mod = match impl_trait_ref { - None => false, - Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == Some(parent_def_id), - }; - - if !in_self_mod && !in_trait_mod { - // If the impl is not co-located with either self-type or - // trait-type, then fallback to a format that identifies - // the module more clearly. - self.path_append_impl( - |cx| cx.print_def_path(parent_def_id, &[]), - &key.disambiguated_data, - self_ty, - impl_trait_ref, - ) - } else { - // Otherwise, try to give a good form that would be valid language - // syntax. Preferably using associated item notation. - self.path_qualified(self_ty, impl_trait_ref) - } - } -} - -/// As a heuristic, when we see an impl, if we see that the -/// 'self type' is a type defined in the same module as the impl, -/// we can omit including the path to the impl itself. This -/// function tries to find a "characteristic `DefId`" for a -/// type. It's just a heuristic so it makes some questionable -/// decisions and we may want to adjust it later. -pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> { - match ty.kind { - ty::Adt(adt_def, _) => Some(adt_def.did), - - ty::Dynamic(data, ..) => data.principal_def_id(), - - ty::Array(subty, _) | ty::Slice(subty) => characteristic_def_id_of_type(subty), - - ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty), - - ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty), - - ty::Tuple(ref tys) => { - tys.iter().filter_map(|ty| characteristic_def_id_of_type(ty.expect_ty())).next() - } - - ty::FnDef(def_id, _) - | ty::Closure(def_id, _) - | ty::Generator(def_id, _, _) - | ty::Foreign(def_id) => Some(def_id), - - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Str - | ty::FnPtr(_) - | ty::Projection(_) - | ty::Placeholder(..) - | ty::UnnormalizedProjection(..) - | ty::Param(_) - | ty::Opaque(..) - | ty::Infer(_) - | ty::Bound(..) - | ty::Error - | ty::GeneratorWitness(..) - | ty::Never - | ty::Float(_) => None, - } -} - -impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::RegionKind { - type Output = P::Region; - type Error = P::Error; - fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { - cx.print_region(self) - } -} - -impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'_> { - type Output = P::Region; - type Error = P::Error; - fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { - cx.print_region(self) - } -} - -impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> { - type Output = P::Type; - type Error = P::Error; - fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { - cx.print_type(self) - } -} - -impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> { - type Output = P::DynExistential; - type Error = P::Error; - fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { - cx.print_dyn_existential(self) - } -} - -impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::Const<'tcx> { - type Output = P::Const; - type Error = P::Error; - fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { - cx.print_const(self) - } -} diff --git a/src/librustc/ty/print/obsolete.rs b/src/librustc/ty/print/obsolete.rs deleted file mode 100644 index 7605d44c7f3..00000000000 --- a/src/librustc/ty/print/obsolete.rs +++ /dev/null @@ -1,250 +0,0 @@ -//! Allows for producing a unique string key for a mono item. -//! These keys are used by the handwritten auto-tests, so they need to be -//! predictable and human-readable. -//! -//! Note: A lot of this could looks very similar to what's already in `ty::print`. -//! FIXME(eddyb) implement a custom `PrettyPrinter` for this. - -use rustc::bug; -use rustc::ty::subst::SubstsRef; -use rustc::ty::{self, Const, Instance, Ty, TyCtxt}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use std::fmt::Write; -use std::iter; - -/// Same as `unique_type_name()` but with the result pushed onto the given -/// `output` parameter. -pub struct DefPathBasedNames<'tcx> { - tcx: TyCtxt<'tcx>, - omit_disambiguators: bool, - omit_local_crate_name: bool, -} - -impl DefPathBasedNames<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, omit_disambiguators: bool, omit_local_crate_name: bool) -> Self { - DefPathBasedNames { tcx, omit_disambiguators, omit_local_crate_name } - } - - // Pushes the type name of the specified type to the provided string. - // If `debug` is true, printing normally unprintable types is allowed - // (e.g. `ty::GeneratorWitness`). This parameter should only be set when - // this method is being used for logging purposes (e.g. with `debug!` or `info!`) - // When being used for codegen purposes, `debug` should be set to `false` - // in order to catch unexpected types that should never end up in a type name. - pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) { - match t.kind { - ty::Bool => output.push_str("bool"), - ty::Char => output.push_str("char"), - ty::Str => output.push_str("str"), - ty::Never => output.push_str("!"), - ty::Int(ty) => output.push_str(ty.name_str()), - ty::Uint(ty) => output.push_str(ty.name_str()), - ty::Float(ty) => output.push_str(ty.name_str()), - ty::Adt(adt_def, substs) => { - self.push_def_path(adt_def.did, output); - self.push_generic_params(substs, iter::empty(), output, debug); - } - ty::Tuple(component_types) => { - output.push('('); - for &component_type in component_types { - self.push_type_name(component_type.expect_ty(), output, debug); - output.push_str(", "); - } - if !component_types.is_empty() { - output.pop(); - output.pop(); - } - output.push(')'); - } - ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => { - output.push('*'); - match mutbl { - hir::Mutability::Not => output.push_str("const "), - hir::Mutability::Mut => output.push_str("mut "), - } - - self.push_type_name(inner_type, output, debug); - } - ty::Ref(_, inner_type, mutbl) => { - output.push('&'); - output.push_str(mutbl.prefix_str()); - - self.push_type_name(inner_type, output, debug); - } - ty::Array(inner_type, len) => { - output.push('['); - self.push_type_name(inner_type, output, debug); - let len = len.eval_usize(self.tcx, ty::ParamEnv::reveal_all()); - write!(output, "; {}", len).unwrap(); - output.push(']'); - } - ty::Slice(inner_type) => { - output.push('['); - self.push_type_name(inner_type, output, debug); - output.push(']'); - } - ty::Dynamic(ref trait_data, ..) => { - if let Some(principal) = trait_data.principal() { - self.push_def_path(principal.def_id(), output); - self.push_generic_params( - principal.skip_binder().substs, - trait_data.projection_bounds(), - output, - debug, - ); - } else { - output.push_str("dyn '_"); - } - } - ty::Foreign(did) => self.push_def_path(did, output), - ty::FnDef(..) | ty::FnPtr(_) => { - let sig = t.fn_sig(self.tcx); - output.push_str(sig.unsafety().prefix_str()); - - let abi = sig.abi(); - if abi != ::rustc_target::spec::abi::Abi::Rust { - output.push_str("extern \""); - output.push_str(abi.name()); - output.push_str("\" "); - } - - output.push_str("fn("); - - let sig = - self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - - if !sig.inputs().is_empty() { - for ¶meter_type in sig.inputs() { - self.push_type_name(parameter_type, output, debug); - output.push_str(", "); - } - output.pop(); - output.pop(); - } - - if sig.c_variadic { - if !sig.inputs().is_empty() { - output.push_str(", ..."); - } else { - output.push_str("..."); - } - } - - output.push(')'); - - if !sig.output().is_unit() { - output.push_str(" -> "); - self.push_type_name(sig.output(), output, debug); - } - } - ty::Generator(def_id, substs, _) | ty::Closure(def_id, substs) => { - self.push_def_path(def_id, output); - let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id)); - let substs = substs.truncate_to(self.tcx, generics); - self.push_generic_params(substs, iter::empty(), output, debug); - } - ty::Error - | ty::Bound(..) - | ty::Infer(_) - | ty::Placeholder(..) - | ty::UnnormalizedProjection(..) - | ty::Projection(..) - | ty::Param(_) - | ty::GeneratorWitness(_) - | ty::Opaque(..) => { - if debug { - output.push_str(&format!("`{:?}`", t)); - } else { - bug!( - "DefPathBasedNames: trying to create type name for unexpected type: {:?}", - t, - ); - } - } - } - } - - // Pushes the the name of the specified const to the provided string. - // If `debug` is true, the unprintable types of constants will be printed with `fmt::Debug` - // (see `push_type_name` for more details). - pub fn push_const_name(&self, ct: &Const<'tcx>, output: &mut String, debug: bool) { - write!(output, "{}", ct).unwrap(); - output.push_str(": "); - self.push_type_name(ct.ty, output, debug); - } - - pub fn push_def_path(&self, def_id: DefId, output: &mut String) { - let def_path = self.tcx.def_path(def_id); - - // some_crate:: - if !(self.omit_local_crate_name && def_id.is_local()) { - output.push_str(&self.tcx.crate_name(def_path.krate).as_str()); - output.push_str("::"); - } - - // foo::bar::ItemName:: - for part in self.tcx.def_path(def_id).data { - if self.omit_disambiguators { - write!(output, "{}::", part.data.as_symbol()).unwrap(); - } else { - write!(output, "{}[{}]::", part.data.as_symbol(), part.disambiguator).unwrap(); - } - } - - // remove final "::" - output.pop(); - output.pop(); - } - - fn push_generic_params<I>( - &self, - substs: SubstsRef<'tcx>, - projections: I, - output: &mut String, - debug: bool, - ) where - I: Iterator<Item = ty::PolyExistentialProjection<'tcx>>, - { - let mut projections = projections.peekable(); - if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() { - return; - } - - output.push('<'); - - for type_parameter in substs.types() { - self.push_type_name(type_parameter, output, debug); - output.push_str(", "); - } - - for projection in projections { - let projection = projection.skip_binder(); - let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str(); - output.push_str(name); - output.push_str("="); - self.push_type_name(projection.ty, output, debug); - output.push_str(", "); - } - - for const_parameter in substs.consts() { - self.push_const_name(const_parameter, output, debug); - output.push_str(", "); - } - - output.pop(); - output.pop(); - - output.push('>'); - } - - pub fn push_instance_as_string( - &self, - instance: Instance<'tcx>, - output: &mut String, - debug: bool, - ) { - self.push_def_path(instance.def_id(), output); - self.push_generic_params(instance.substs, iter::empty(), output, debug); - } -} diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs deleted file mode 100644 index 0726bf30d3b..00000000000 --- a/src/librustc/ty/print/pretty.rs +++ /dev/null @@ -1,1853 +0,0 @@ -use crate::hir::map::{DefPathData, DisambiguatedDefPathData}; -use crate::middle::cstore::{ExternCrate, ExternCrateSource}; -use crate::middle::region; -use crate::mir::interpret::{sign_extend, truncate, ConstValue, Scalar}; -use crate::ty::layout::{Integer, IntegerExt, Size}; -use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; -use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable}; -use rustc_hir as hir; -use rustc_hir::def::{DefKind, Namespace}; -use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; - -use rustc_apfloat::ieee::{Double, Single}; -use rustc_apfloat::Float; -use rustc_attr::{SignedInt, UnsignedInt}; -use rustc_span::symbol::{kw, Symbol}; -use rustc_target::spec::abi::Abi; -use syntax::ast; - -use std::cell::Cell; -use std::collections::BTreeMap; -use std::fmt::{self, Write as _}; -use std::ops::{Deref, DerefMut}; - -// `pretty` is a separate module only for organization. -use super::*; - -macro_rules! p { - (@write($($data:expr),+)) => { - write!(scoped_cx!(), $($data),+)? - }; - (@print($x:expr)) => { - scoped_cx!() = $x.print(scoped_cx!())? - }; - (@$method:ident($($arg:expr),*)) => { - scoped_cx!() = scoped_cx!().$method($($arg),*)? - }; - ($($kind:ident $data:tt),+) => {{ - $(p!(@$kind $data);)+ - }}; -} -macro_rules! define_scoped_cx { - ($cx:ident) => { - #[allow(unused_macros)] - macro_rules! scoped_cx { - () => { - $cx - }; - } - }; -} - -thread_local! { - static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false); - static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false); - static NO_QUERIES: Cell<bool> = Cell::new(false); -} - -/// Avoids running any queries during any prints that occur -/// during the closure. This may alter the appearance of some -/// types (e.g. forcing verbose printing for opaque types). -/// This method is used during some queries (e.g. `predicates_of` -/// for opaque types), to ensure that any debug printing that -/// occurs during the query computation does not end up recursively -/// calling the same query. -pub fn with_no_queries<F: FnOnce() -> R, R>(f: F) -> R { - NO_QUERIES.with(|no_queries| { - let old = no_queries.replace(true); - let result = f(); - no_queries.set(old); - result - }) -} - -/// Force us to name impls with just the filename/line number. We -/// normally try to use types. But at some points, notably while printing -/// cycle errors, this can result in extra or suboptimal error output, -/// so this variable disables that check. -pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R { - FORCE_IMPL_FILENAME_LINE.with(|force| { - let old = force.replace(true); - let result = f(); - force.set(old); - result - }) -} - -/// Adds the `crate::` prefix to paths where appropriate. -pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R { - SHOULD_PREFIX_WITH_CRATE.with(|flag| { - let old = flag.replace(true); - let result = f(); - flag.set(old); - result - }) -} - -/// The "region highlights" are used to control region printing during -/// specific error messages. When a "region highlight" is enabled, it -/// gives an alternate way to print specific regions. For now, we -/// always print those regions using a number, so something like "`'0`". -/// -/// Regions not selected by the region highlight mode are presently -/// unaffected. -#[derive(Copy, Clone, Default)] -pub struct RegionHighlightMode { - /// If enabled, when we see the selected region, use "`'N`" - /// instead of the ordinary behavior. - highlight_regions: [Option<(ty::RegionKind, usize)>; 3], - - /// If enabled, when printing a "free region" that originated from - /// the given `ty::BoundRegion`, print it as "`'1`". Free regions that would ordinarily - /// have names print as normal. - /// - /// This is used when you have a signature like `fn foo(x: &u32, - /// y: &'a u32)` and we want to give a name to the region of the - /// reference `x`. - highlight_bound_region: Option<(ty::BoundRegion, usize)>, -} - -impl RegionHighlightMode { - /// If `region` and `number` are both `Some`, invokes - /// `highlighting_region`. - pub fn maybe_highlighting_region( - &mut self, - region: Option<ty::Region<'_>>, - number: Option<usize>, - ) { - if let Some(k) = region { - if let Some(n) = number { - self.highlighting_region(k, n); - } - } - } - - /// Highlights the region inference variable `vid` as `'N`. - pub fn highlighting_region(&mut self, region: ty::Region<'_>, number: usize) { - let num_slots = self.highlight_regions.len(); - let first_avail_slot = - self.highlight_regions.iter_mut().filter(|s| s.is_none()).next().unwrap_or_else(|| { - bug!("can only highlight {} placeholders at a time", num_slots,) - }); - *first_avail_slot = Some((*region, number)); - } - - /// Convenience wrapper for `highlighting_region`. - pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) { - self.highlighting_region(&ty::ReVar(vid), number) - } - - /// Returns `Some(n)` with the number to use for the given region, if any. - fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> { - self.highlight_regions - .iter() - .filter_map(|h| match h { - Some((r, n)) if r == region => Some(*n), - _ => None, - }) - .next() - } - - /// Highlight the given bound region. - /// We can only highlight one bound region at a time. See - /// the field `highlight_bound_region` for more detailed notes. - pub fn highlighting_bound_region(&mut self, br: ty::BoundRegion, number: usize) { - assert!(self.highlight_bound_region.is_none()); - self.highlight_bound_region = Some((br, number)); - } -} - -/// Trait for printers that pretty-print using `fmt::Write` to the printer. -pub trait PrettyPrinter<'tcx>: - Printer< - 'tcx, - Error = fmt::Error, - Path = Self, - Region = Self, - Type = Self, - DynExistential = Self, - Const = Self, - > + fmt::Write -{ - /// Like `print_def_path` but for value paths. - fn print_value_path( - self, - def_id: DefId, - substs: &'tcx [GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { - self.print_def_path(def_id, substs) - } - - fn in_binder<T>(self, value: &ty::Binder<T>) -> Result<Self, Self::Error> - where - T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>, - { - value.skip_binder().print(self) - } - - /// Prints comma-separated elements. - fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error> - where - T: Print<'tcx, Self, Output = Self, Error = Self::Error>, - { - if let Some(first) = elems.next() { - self = first.print(self)?; - for elem in elems { - self.write_str(", ")?; - self = elem.print(self)?; - } - } - Ok(self) - } - - /// Prints `<...>` around what `f` prints. - fn generic_delimiters( - self, - f: impl FnOnce(Self) -> Result<Self, Self::Error>, - ) -> Result<Self, Self::Error>; - - /// Returns `true` if the region should be printed in - /// optional positions, e.g., `&'a T` or `dyn Tr + 'b`. - /// This is typically the case for all non-`'_` regions. - fn region_should_not_be_omitted(&self, region: ty::Region<'_>) -> bool; - - // Defaults (should not be overriden): - - /// If possible, this returns a global path resolving to `def_id` that is visible - /// from at least one local module, and returns `true`. If the crate defining `def_id` is - /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`. - fn try_print_visible_def_path(self, def_id: DefId) -> Result<(Self, bool), Self::Error> { - let mut callers = Vec::new(); - self.try_print_visible_def_path_recur(def_id, &mut callers) - } - - /// Does the work of `try_print_visible_def_path`, building the - /// full definition path recursively before attempting to - /// post-process it into the valid and visible version that - /// accounts for re-exports. - /// - /// This method should only be callled by itself or - /// `try_print_visible_def_path`. - /// - /// `callers` is a chain of visible_parent's leading to `def_id`, - /// to support cycle detection during recursion. - fn try_print_visible_def_path_recur( - mut self, - def_id: DefId, - callers: &mut Vec<DefId>, - ) -> Result<(Self, bool), Self::Error> { - define_scoped_cx!(self); - - debug!("try_print_visible_def_path: def_id={:?}", def_id); - - // If `def_id` is a direct or injected extern crate, return the - // path to the crate followed by the path to the item within the crate. - if def_id.index == CRATE_DEF_INDEX { - let cnum = def_id.krate; - - if cnum == LOCAL_CRATE { - return Ok((self.path_crate(cnum)?, true)); - } - - // In local mode, when we encounter a crate other than - // LOCAL_CRATE, execution proceeds in one of two ways: - // - // 1. For a direct dependency, where user added an - // `extern crate` manually, we put the `extern - // crate` as the parent. So you wind up with - // something relative to the current crate. - // 2. For an extern inferred from a path or an indirect crate, - // where there is no explicit `extern crate`, we just prepend - // the crate name. - match self.tcx().extern_crate(def_id) { - Some(&ExternCrate { - src: ExternCrateSource::Extern(def_id), - dependency_of: LOCAL_CRATE, - span, - .. - }) => { - debug!("try_print_visible_def_path: def_id={:?}", def_id); - return Ok(( - if !span.is_dummy() { - self.print_def_path(def_id, &[])? - } else { - self.path_crate(cnum)? - }, - true, - )); - } - None => { - return Ok((self.path_crate(cnum)?, true)); - } - _ => {} - } - } - - if def_id.is_local() { - return Ok((self, false)); - } - - let visible_parent_map = self.tcx().visible_parent_map(LOCAL_CRATE); - - let mut cur_def_key = self.tcx().def_key(def_id); - debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key); - - // For a constructor, we want the name of its parent rather than <unnamed>. - match cur_def_key.disambiguated_data.data { - DefPathData::Ctor => { - let parent = DefId { - krate: def_id.krate, - index: cur_def_key - .parent - .expect("`DefPathData::Ctor` / `VariantData` missing a parent"), - }; - - cur_def_key = self.tcx().def_key(parent); - } - _ => {} - } - - let visible_parent = match visible_parent_map.get(&def_id).cloned() { - Some(parent) => parent, - None => return Ok((self, false)), - }; - if callers.contains(&visible_parent) { - return Ok((self, false)); - } - callers.push(visible_parent); - // HACK(eddyb) this bypasses `path_append`'s prefix printing to avoid - // knowing ahead of time whether the entire path will succeed or not. - // To support printers that do not implement `PrettyPrinter`, a `Vec` or - // linked list on the stack would need to be built, before any printing. - match self.try_print_visible_def_path_recur(visible_parent, callers)? { - (cx, false) => return Ok((cx, false)), - (cx, true) => self = cx, - } - callers.pop(); - let actual_parent = self.tcx().parent(def_id); - debug!( - "try_print_visible_def_path: visible_parent={:?} actual_parent={:?}", - visible_parent, actual_parent, - ); - - let mut data = cur_def_key.disambiguated_data.data; - debug!( - "try_print_visible_def_path: data={:?} visible_parent={:?} actual_parent={:?}", - data, visible_parent, actual_parent, - ); - - match data { - // In order to output a path that could actually be imported (valid and visible), - // we need to handle re-exports correctly. - // - // For example, take `std::os::unix::process::CommandExt`, this trait is actually - // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing). - // - // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is - // private so the "true" path to `CommandExt` isn't accessible. - // - // In this case, the `visible_parent_map` will look something like this: - // - // (child) -> (parent) - // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process` - // `std::sys::unix::ext::process` -> `std::sys::unix::ext` - // `std::sys::unix::ext` -> `std::os` - // - // This is correct, as the visible parent of `std::sys::unix::ext` is in fact - // `std::os`. - // - // When printing the path to `CommandExt` and looking at the `cur_def_key` that - // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go - // to the parent - resulting in a mangled path like - // `std::os::ext::process::CommandExt`. - // - // Instead, we must detect that there was a re-export and instead print `unix` - // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To - // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with - // the visible parent (`std::os`). If these do not match, then we iterate over - // the children of the visible parent (as was done when computing - // `visible_parent_map`), looking for the specific child we currently have and then - // have access to the re-exported name. - DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => { - let reexport = self - .tcx() - .item_children(visible_parent) - .iter() - .find(|child| child.res.def_id() == def_id) - .map(|child| child.ident.name); - if let Some(reexport) = reexport { - *name = reexport; - } - } - // Re-exported `extern crate` (#43189). - DefPathData::CrateRoot => { - data = DefPathData::TypeNs(self.tcx().original_crate_name(def_id.krate)); - } - _ => {} - } - debug!("try_print_visible_def_path: data={:?}", data); - - Ok((self.path_append(Ok, &DisambiguatedDefPathData { data, disambiguator: 0 })?, true)) - } - - fn pretty_path_qualified( - self, - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - if trait_ref.is_none() { - // Inherent impls. Try to print `Foo::bar` for an inherent - // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is - // anything other than a simple path. - match self_ty.kind { - ty::Adt(..) - | ty::Foreign(_) - | ty::Bool - | ty::Char - | ty::Str - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) => { - return self_ty.print(self); - } - - _ => {} - } - } - - self.generic_delimiters(|mut cx| { - define_scoped_cx!(cx); - - p!(print(self_ty)); - if let Some(trait_ref) = trait_ref { - p!(write(" as "), print(trait_ref.print_only_trait_path())); - } - Ok(cx) - }) - } - - fn pretty_path_append_impl( - mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - self = print_prefix(self)?; - - self.generic_delimiters(|mut cx| { - define_scoped_cx!(cx); - - p!(write("impl ")); - if let Some(trait_ref) = trait_ref { - p!(print(trait_ref.print_only_trait_path()), write(" for ")); - } - p!(print(self_ty)); - - Ok(cx) - }) - } - - fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { - define_scoped_cx!(self); - - match ty.kind { - ty::Bool => p!(write("bool")), - ty::Char => p!(write("char")), - ty::Int(t) => p!(write("{}", t.name_str())), - ty::Uint(t) => p!(write("{}", t.name_str())), - ty::Float(t) => p!(write("{}", t.name_str())), - ty::RawPtr(ref tm) => { - p!(write( - "*{} ", - match tm.mutbl { - hir::Mutability::Mut => "mut", - hir::Mutability::Not => "const", - } - )); - p!(print(tm.ty)) - } - ty::Ref(r, ty, mutbl) => { - p!(write("&")); - if self.region_should_not_be_omitted(r) { - p!(print(r), write(" ")); - } - p!(print(ty::TypeAndMut { ty, mutbl })) - } - ty::Never => p!(write("!")), - ty::Tuple(ref tys) => { - p!(write("(")); - let mut tys = tys.iter(); - if let Some(&ty) = tys.next() { - p!(print(ty), write(",")); - if let Some(&ty) = tys.next() { - p!(write(" "), print(ty)); - for &ty in tys { - p!(write(", "), print(ty)); - } - } - } - p!(write(")")) - } - ty::FnDef(def_id, substs) => { - let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs); - p!(print(sig), write(" {{"), print_value_path(def_id, substs), write("}}")); - } - ty::FnPtr(ref bare_fn) => p!(print(bare_fn)), - ty::Infer(infer_ty) => { - if let ty::TyVar(ty_vid) = infer_ty { - if let Some(name) = self.infer_ty_name(ty_vid) { - p!(write("{}", name)) - } else { - p!(write("{}", infer_ty)) - } - } else { - p!(write("{}", infer_ty)) - } - } - ty::Error => p!(write("[type error]")), - ty::Param(ref param_ty) => p!(write("{}", param_ty)), - ty::Bound(debruijn, bound_ty) => match bound_ty.kind { - ty::BoundTyKind::Anon => { - if debruijn == ty::INNERMOST { - p!(write("^{}", bound_ty.var.index())) - } else { - p!(write("^{}_{}", debruijn.index(), bound_ty.var.index())) - } - } - - ty::BoundTyKind::Param(p) => p!(write("{}", p)), - }, - ty::Adt(def, substs) => { - p!(print_def_path(def.did, substs)); - } - ty::Dynamic(data, r) => { - let print_r = self.region_should_not_be_omitted(r); - if print_r { - p!(write("(")); - } - p!(write("dyn "), print(data)); - if print_r { - p!(write(" + "), print(r), write(")")); - } - } - ty::Foreign(def_id) => { - p!(print_def_path(def_id, &[])); - } - ty::Projection(ref data) => p!(print(data)), - ty::UnnormalizedProjection(ref data) => { - p!(write("Unnormalized("), print(data), write(")")) - } - ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)), - ty::Opaque(def_id, substs) => { - // FIXME(eddyb) print this with `print_def_path`. - // We use verbose printing in 'NO_QUERIES' mode, to - // avoid needing to call `predicates_of`. This should - // only affect certain debug messages (e.g. messages printed - // from `rustc::ty` during the computation of `tcx.predicates_of`), - // and should have no effect on any compiler output. - if self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get()) { - p!(write("Opaque({:?}, {:?})", def_id, substs)); - return Ok(self); - } - - return Ok(with_no_queries(|| { - let def_key = self.tcx().def_key(def_id); - if let Some(name) = def_key.disambiguated_data.data.get_opt_name() { - p!(write("{}", name)); - let mut substs = substs.iter(); - // FIXME(eddyb) print this with `print_def_path`. - if let Some(first) = substs.next() { - p!(write("::<")); - p!(print(first)); - for subst in substs { - p!(write(", "), print(subst)); - } - p!(write(">")); - } - return Ok(self); - } - // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, - // by looking up the projections associated with the def_id. - let bounds = self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs); - - let mut first = true; - let mut is_sized = false; - p!(write("impl")); - for predicate in bounds.predicates { - if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { - // Don't print +Sized, but rather +?Sized if absent. - if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() { - is_sized = true; - continue; - } - - p!( - write("{}", if first { " " } else { "+" }), - print(trait_ref.print_only_trait_path()) - ); - first = false; - } - } - if !is_sized { - p!(write("{}?Sized", if first { " " } else { "+" })); - } else if first { - p!(write(" Sized")); - } - Ok(self) - })?); - } - ty::Str => p!(write("str")), - ty::Generator(did, substs, movability) => { - let upvar_tys = substs.as_generator().upvar_tys(did, self.tcx()); - let witness = substs.as_generator().witness(did, self.tcx()); - match movability { - hir::Movability::Movable => p!(write("[generator")), - hir::Movability::Static => p!(write("[static generator")), - } - - // FIXME(eddyb) should use `def_span`. - if let Some(hir_id) = self.tcx().hir().as_local_hir_id(did) { - p!(write("@{:?}", self.tcx().hir().span(hir_id))); - let mut sep = " "; - for (&var_id, upvar_ty) in - self.tcx().upvars(did).as_ref().iter().flat_map(|v| v.keys()).zip(upvar_tys) - { - p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty)); - sep = ", "; - } - } else { - // Cross-crate closure types should only be - // visible in codegen bug reports, I imagine. - p!(write("@{:?}", did)); - let mut sep = " "; - for (index, upvar_ty) in upvar_tys.enumerate() { - p!(write("{}{}:", sep, index), print(upvar_ty)); - sep = ", "; - } - } - - p!(write(" "), print(witness), write("]")) - } - ty::GeneratorWitness(types) => { - p!(in_binder(&types)); - } - ty::Closure(did, substs) => { - let upvar_tys = substs.as_closure().upvar_tys(did, self.tcx()); - p!(write("[closure")); - - // FIXME(eddyb) should use `def_span`. - if let Some(hir_id) = self.tcx().hir().as_local_hir_id(did) { - if self.tcx().sess.opts.debugging_opts.span_free_formats { - p!(write("@"), print_def_path(did, substs)); - } else { - p!(write("@{:?}", self.tcx().hir().span(hir_id))); - } - let mut sep = " "; - for (&var_id, upvar_ty) in - self.tcx().upvars(did).as_ref().iter().flat_map(|v| v.keys()).zip(upvar_tys) - { - p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty)); - sep = ", "; - } - } else { - // Cross-crate closure types should only be - // visible in codegen bug reports, I imagine. - p!(write("@{:?}", did)); - let mut sep = " "; - for (index, upvar_ty) in upvar_tys.enumerate() { - p!(write("{}{}:", sep, index), print(upvar_ty)); - sep = ", "; - } - } - - if self.tcx().sess.verbose() { - p!(write( - " closure_kind_ty={:?} closure_sig_ty={:?}", - substs.as_closure().kind_ty(did, self.tcx()), - substs.as_closure().sig_ty(did, self.tcx()) - )); - } - - p!(write("]")) - } - ty::Array(ty, sz) => { - p!(write("["), print(ty), write("; ")); - if self.tcx().sess.verbose() { - p!(write("{:?}", sz)); - } else if let ty::ConstKind::Unevaluated(..) = sz.val { - // do not try to evalute unevaluated constants. If we are const evaluating an - // array length anon const, rustc will (with debug assertions) print the - // constant's path. Which will end up here again. - p!(write("_")); - } else if let Some(n) = sz.try_eval_usize(self.tcx(), ty::ParamEnv::empty()) { - p!(write("{}", n)); - } else { - p!(write("_")); - } - p!(write("]")) - } - ty::Slice(ty) => p!(write("["), print(ty), write("]")), - } - - Ok(self) - } - - fn infer_ty_name(&self, _: ty::TyVid) -> Option<String> { - None - } - - fn pretty_print_dyn_existential( - mut self, - predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { - define_scoped_cx!(self); - - // Generate the main trait ref, including associated types. - let mut first = true; - - if let Some(principal) = predicates.principal() { - p!(print_def_path(principal.def_id, &[])); - - let mut resugared = false; - - // Special-case `Fn(...) -> ...` and resugar it. - let fn_trait_kind = self.tcx().fn_trait_kind_from_lang_item(principal.def_id); - if !self.tcx().sess.verbose() && fn_trait_kind.is_some() { - if let ty::Tuple(ref args) = principal.substs.type_at(0).kind { - let mut projections = predicates.projection_bounds(); - if let (Some(proj), None) = (projections.next(), projections.next()) { - let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect(); - p!(pretty_fn_sig(&tys, false, proj.ty)); - resugared = true; - } - } - } - - // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`, - // in order to place the projections inside the `<...>`. - if !resugared { - // Use a type that can't appear in defaults of type parameters. - let dummy_self = self.tcx().mk_ty_infer(ty::FreshTy(0)); - let principal = principal.with_self_ty(self.tcx(), dummy_self); - - let args = self.generic_args_to_print( - self.tcx().generics_of(principal.def_id), - principal.substs, - ); - - // Don't print `'_` if there's no unerased regions. - let print_regions = args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Lifetime(r) => *r != ty::ReErased, - _ => false, - }); - let mut args = args.iter().cloned().filter(|arg| match arg.unpack() { - GenericArgKind::Lifetime(_) => print_regions, - _ => true, - }); - let mut projections = predicates.projection_bounds(); - - let arg0 = args.next(); - let projection0 = projections.next(); - if arg0.is_some() || projection0.is_some() { - let args = arg0.into_iter().chain(args); - let projections = projection0.into_iter().chain(projections); - - p!(generic_delimiters(|mut cx| { - cx = cx.comma_sep(args)?; - if arg0.is_some() && projection0.is_some() { - write!(cx, ", ")?; - } - cx.comma_sep(projections) - })); - } - } - first = false; - } - - // Builtin bounds. - // FIXME(eddyb) avoid printing twice (needed to ensure - // that the auto traits are sorted *and* printed via cx). - let mut auto_traits: Vec<_> = - predicates.auto_traits().map(|did| (self.tcx().def_path_str(did), did)).collect(); - - // The auto traits come ordered by `DefPathHash`. While - // `DefPathHash` is *stable* in the sense that it depends on - // neither the host nor the phase of the moon, it depends - // "pseudorandomly" on the compiler version and the target. - // - // To avoid that causing instabilities in compiletest - // output, sort the auto-traits alphabetically. - auto_traits.sort(); - - for (_, def_id) in auto_traits { - if !first { - p!(write(" + ")); - } - first = false; - - p!(print_def_path(def_id, &[])); - } - - Ok(self) - } - - fn pretty_fn_sig( - mut self, - inputs: &[Ty<'tcx>], - c_variadic: bool, - output: Ty<'tcx>, - ) -> Result<Self, Self::Error> { - define_scoped_cx!(self); - - p!(write("(")); - let mut inputs = inputs.iter(); - if let Some(&ty) = inputs.next() { - p!(print(ty)); - for &ty in inputs { - p!(write(", "), print(ty)); - } - if c_variadic { - p!(write(", ...")); - } - } - p!(write(")")); - if !output.is_unit() { - p!(write(" -> "), print(output)); - } - - Ok(self) - } - - fn pretty_print_const( - mut self, - ct: &'tcx ty::Const<'tcx>, - print_ty: bool, - ) -> Result<Self::Const, Self::Error> { - define_scoped_cx!(self); - - if self.tcx().sess.verbose() { - p!(write("Const({:?}: {:?})", ct.val, ct.ty)); - return Ok(self); - } - - macro_rules! print_underscore { - () => {{ - p!(write("_")); - if print_ty { - p!(write(": "), print(ct.ty)); - } - }}; - } - - match (ct.val, &ct.ty.kind) { - (_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)), - (ty::ConstKind::Unevaluated(did, substs, promoted), _) => { - if let Some(promoted) = promoted { - p!(print_value_path(did, substs)); - p!(write("::{:?}", promoted)); - } else { - match self.tcx().def_kind(did) { - Some(DefKind::Static) - | Some(DefKind::Const) - | Some(DefKind::AssocConst) => p!(print_value_path(did, substs)), - _ => { - if did.is_local() { - let span = self.tcx().def_span(did); - if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) - { - p!(write("{}", snip)) - } else { - print_underscore!() - } - } else { - print_underscore!() - } - } - } - } - } - (ty::ConstKind::Infer(..), _) => print_underscore!(), - (ty::ConstKind::Param(ParamConst { name, .. }), _) => p!(write("{}", name)), - (ty::ConstKind::Value(value), _) => { - return self.pretty_print_const_value(value, ct.ty, print_ty); - } - - _ => { - // fallback - p!(write("{:?}", ct.val)); - if print_ty { - p!(write(": "), print(ct.ty)); - } - } - }; - Ok(self) - } - - fn pretty_print_const_value( - mut self, - ct: ConstValue<'tcx>, - ty: Ty<'tcx>, - print_ty: bool, - ) -> Result<Self::Const, Self::Error> { - define_scoped_cx!(self); - - if self.tcx().sess.verbose() { - p!(write("ConstValue({:?}: {:?})", ct, ty)); - return Ok(self); - } - - let u8 = self.tcx().types.u8; - - match (ct, &ty.kind) { - (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Bool) => { - p!(write("{}", if data == 0 { "false" } else { "true" })) - } - (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F32)) => { - p!(write("{}f32", Single::from_bits(data))) - } - (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F64)) => { - p!(write("{}f64", Double::from_bits(data))) - } - (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Uint(ui)) => { - let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size(); - let max = truncate(u128::max_value(), bit_size); - - let ui_str = ui.name_str(); - if data == max { - p!(write("std::{}::MAX", ui_str)) - } else { - p!(write("{}{}", data, ui_str)) - }; - } - (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Int(i)) => { - let bit_size = Integer::from_attr(&self.tcx(), SignedInt(*i)).size().bits() as u128; - let min = 1u128 << (bit_size - 1); - let max = min - 1; - - let ty = self.tcx().lift(&ty).unwrap(); - let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; - let i_str = i.name_str(); - match data { - d if d == min => p!(write("std::{}::MIN", i_str)), - d if d == max => p!(write("std::{}::MAX", i_str)), - _ => p!(write("{}{}", sign_extend(data, size) as i128, i_str)), - } - } - (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Char) => { - p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap())) - } - (ConstValue::Scalar(_), ty::RawPtr(_)) => p!(write("{{pointer}}")), - (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::FnPtr(_)) => { - let instance = { - let alloc_map = self.tcx().alloc_map.lock(); - alloc_map.unwrap_fn(ptr.alloc_id) - }; - p!(print_value_path(instance.def_id(), instance.substs)); - } - _ => { - let printed = if let ty::Ref(_, ref_ty, _) = ty.kind { - let byte_str = match (ct, &ref_ty.kind) { - (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => { - let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty()); - Some( - self.tcx() - .alloc_map - .lock() - .unwrap_memory(ptr.alloc_id) - .get_bytes(&self.tcx(), ptr, Size::from_bytes(n)) - .unwrap(), - ) - } - (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => { - // The `inspect` here is okay since we checked the bounds, and there are - // no relocations (we have an active slice reference here). We don't use - // this result to affect interpreter execution. - Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end)) - } - _ => None, - }; - - if let Some(byte_str) = byte_str { - p!(write("b\"")); - for &c in byte_str { - for e in std::ascii::escape_default(c) { - self.write_char(e as char)?; - } - } - p!(write("\"")); - true - } else if let (ConstValue::Slice { data, start, end }, ty::Str) = - (ct, &ref_ty.kind) - { - // The `inspect` here is okay since we checked the bounds, and there are no - // relocations (we have an active `str` reference here). We don't use this - // result to affect interpreter execution. - let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end); - let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); - p!(write("{:?}", s)); - true - } else { - false - } - } else { - false - }; - if !printed { - // fallback - p!(write("{:?}", ct)); - if print_ty { - p!(write(": "), print(ty)); - } - } - } - }; - Ok(self) - } -} - -// HACK(eddyb) boxed to avoid moving around a large struct by-value. -pub struct FmtPrinter<'a, 'tcx, F>(Box<FmtPrinterData<'a, 'tcx, F>>); - -pub struct FmtPrinterData<'a, 'tcx, F> { - tcx: TyCtxt<'tcx>, - fmt: F, - - empty_path: bool, - in_value: bool, - - used_region_names: FxHashSet<Symbol>, - region_index: usize, - binder_depth: usize, - - pub region_highlight_mode: RegionHighlightMode, - - pub name_resolver: Option<Box<&'a dyn Fn(ty::sty::TyVid) -> Option<String>>>, -} - -impl<F> Deref for FmtPrinter<'a, 'tcx, F> { - type Target = FmtPrinterData<'a, 'tcx, F>; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl<F> DerefMut for FmtPrinter<'_, '_, F> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl<F> FmtPrinter<'a, 'tcx, F> { - pub fn new(tcx: TyCtxt<'tcx>, fmt: F, ns: Namespace) -> Self { - FmtPrinter(Box::new(FmtPrinterData { - tcx, - fmt, - empty_path: false, - in_value: ns == Namespace::ValueNS, - used_region_names: Default::default(), - region_index: 0, - binder_depth: 0, - region_highlight_mode: RegionHighlightMode::default(), - name_resolver: None, - })) - } -} - -// HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always -// (but also some things just print a `DefId` generally so maybe we need this?) -fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace { - match tcx.def_key(def_id).disambiguated_data.data { - DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::ImplTrait => { - Namespace::TypeNS - } - - DefPathData::ValueNs(..) - | DefPathData::AnonConst - | DefPathData::ClosureExpr - | DefPathData::Ctor => Namespace::ValueNS, - - DefPathData::MacroNs(..) => Namespace::MacroNS, - - _ => Namespace::TypeNS, - } -} - -impl TyCtxt<'t> { - /// Returns a string identifying this `DefId`. This string is - /// suitable for user output. - pub fn def_path_str(self, def_id: DefId) -> String { - self.def_path_str_with_substs(def_id, &[]) - } - - pub fn def_path_str_with_substs(self, def_id: DefId, substs: &'t [GenericArg<'t>]) -> String { - let ns = guess_def_namespace(self, def_id); - debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns); - let mut s = String::new(); - let _ = FmtPrinter::new(self, &mut s, ns).print_def_path(def_id, substs); - s - } -} - -impl<F: fmt::Write> fmt::Write for FmtPrinter<'_, '_, F> { - fn write_str(&mut self, s: &str) -> fmt::Result { - self.fmt.write_str(s) - } -} - -impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { - type Error = fmt::Error; - - type Path = Self; - type Region = Self; - type Type = Self; - type DynExistential = Self; - type Const = Self; - - fn tcx(&'a self) -> TyCtxt<'tcx> { - self.tcx - } - - fn print_def_path( - mut self, - def_id: DefId, - substs: &'tcx [GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { - define_scoped_cx!(self); - - if substs.is_empty() { - match self.try_print_visible_def_path(def_id)? { - (cx, true) => return Ok(cx), - (cx, false) => self = cx, - } - } - - let key = self.tcx.def_key(def_id); - if let DefPathData::Impl = key.disambiguated_data.data { - // Always use types for non-local impls, where types are always - // available, and filename/line-number is mostly uninteresting. - let use_types = !def_id.is_local() || { - // Otherwise, use filename/line-number if forced. - let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get()); - !force_no_types - }; - - if !use_types { - // If no type info is available, fall back to - // pretty printing some span information. This should - // only occur very early in the compiler pipeline. - let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id }; - let span = self.tcx.def_span(def_id); - - self = self.print_def_path(parent_def_id, &[])?; - - // HACK(eddyb) copy of `path_append` to avoid - // constructing a `DisambiguatedDefPathData`. - if !self.empty_path { - write!(self, "::")?; - } - write!(self, "<impl at {:?}>", span)?; - self.empty_path = false; - - return Ok(self); - } - } - - self.default_print_def_path(def_id, substs) - } - - fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { - self.pretty_print_region(region) - } - - fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { - self.pretty_print_type(ty) - } - - fn print_dyn_existential( - self, - predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { - self.pretty_print_dyn_existential(predicates) - } - - fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { - self.pretty_print_const(ct, true) - } - - fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { - self.empty_path = true; - if cnum == LOCAL_CRATE { - if self.tcx.sess.rust_2018() { - // We add the `crate::` keyword on Rust 2018, only when desired. - if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) { - write!(self, "{}", kw::Crate)?; - self.empty_path = false; - } - } - } else { - write!(self, "{}", self.tcx.crate_name(cnum))?; - self.empty_path = false; - } - Ok(self) - } - - fn path_qualified( - mut self, - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - self = self.pretty_path_qualified(self_ty, trait_ref)?; - self.empty_path = false; - Ok(self) - } - - fn path_append_impl( - mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - _disambiguated_data: &DisambiguatedDefPathData, - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - self = self.pretty_path_append_impl( - |mut cx| { - cx = print_prefix(cx)?; - if !cx.empty_path { - write!(cx, "::")?; - } - - Ok(cx) - }, - self_ty, - trait_ref, - )?; - self.empty_path = false; - Ok(self) - } - - fn path_append( - mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error> { - self = print_prefix(self)?; - - // Skip `::{{constructor}}` on tuple/unit structs. - match disambiguated_data.data { - DefPathData::Ctor => return Ok(self), - _ => {} - } - - // FIXME(eddyb) `name` should never be empty, but it - // currently is for `extern { ... }` "foreign modules". - let name = disambiguated_data.data.as_symbol().as_str(); - if !name.is_empty() { - if !self.empty_path { - write!(self, "::")?; - } - if ast::Ident::from_str(&name).is_raw_guess() { - write!(self, "r#")?; - } - write!(self, "{}", name)?; - - // FIXME(eddyb) this will print e.g. `{{closure}}#3`, but it - // might be nicer to use something else, e.g. `{closure#3}`. - let dis = disambiguated_data.disambiguator; - let print_dis = disambiguated_data.data.get_opt_name().is_none() - || dis != 0 && self.tcx.sess.verbose(); - if print_dis { - write!(self, "#{}", dis)?; - } - - self.empty_path = false; - } - - Ok(self) - } - - fn path_generic_args( - mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { - self = print_prefix(self)?; - - // Don't print `'_` if there's no unerased regions. - let print_regions = args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Lifetime(r) => *r != ty::ReErased, - _ => false, - }); - let args = args.iter().cloned().filter(|arg| match arg.unpack() { - GenericArgKind::Lifetime(_) => print_regions, - _ => true, - }); - - if args.clone().next().is_some() { - if self.in_value { - write!(self, "::")?; - } - self.generic_delimiters(|cx| cx.comma_sep(args)) - } else { - Ok(self) - } - } -} - -impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { - fn infer_ty_name(&self, id: ty::TyVid) -> Option<String> { - self.0.name_resolver.as_ref().and_then(|func| func(id)) - } - - fn print_value_path( - mut self, - def_id: DefId, - substs: &'tcx [GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { - let was_in_value = std::mem::replace(&mut self.in_value, true); - self = self.print_def_path(def_id, substs)?; - self.in_value = was_in_value; - - Ok(self) - } - - fn in_binder<T>(self, value: &ty::Binder<T>) -> Result<Self, Self::Error> - where - T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>, - { - self.pretty_in_binder(value) - } - - fn generic_delimiters( - mut self, - f: impl FnOnce(Self) -> Result<Self, Self::Error>, - ) -> Result<Self, Self::Error> { - write!(self, "<")?; - - let was_in_value = std::mem::replace(&mut self.in_value, false); - let mut inner = f(self)?; - inner.in_value = was_in_value; - - write!(inner, ">")?; - Ok(inner) - } - - fn region_should_not_be_omitted(&self, region: ty::Region<'_>) -> bool { - let highlight = self.region_highlight_mode; - if highlight.region_highlighted(region).is_some() { - return true; - } - - if self.tcx.sess.verbose() { - return true; - } - - let identify_regions = self.tcx.sess.opts.debugging_opts.identify_regions; - - match *region { - ty::ReEarlyBound(ref data) => { - data.name != kw::Invalid && data.name != kw::UnderscoreLifetime - } - - ty::ReLateBound(_, br) - | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) - | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { - if let ty::BrNamed(_, name) = br { - if name != kw::Invalid && name != kw::UnderscoreLifetime { - return true; - } - } - - if let Some((region, _)) = highlight.highlight_bound_region { - if br == region { - return true; - } - } - - false - } - - ty::ReScope(_) | ty::ReVar(_) if identify_regions => true, - - ty::ReVar(_) | ty::ReScope(_) | ty::ReErased => false, - - ty::ReStatic | ty::ReEmpty(_) | ty::ReClosureBound(_) => true, - } - } -} - -// HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`. -impl<F: fmt::Write> FmtPrinter<'_, '_, F> { - pub fn pretty_print_region(mut self, region: ty::Region<'_>) -> Result<Self, fmt::Error> { - define_scoped_cx!(self); - - // Watch out for region highlights. - let highlight = self.region_highlight_mode; - if let Some(n) = highlight.region_highlighted(region) { - p!(write("'{}", n)); - return Ok(self); - } - - if self.tcx.sess.verbose() { - p!(write("{:?}", region)); - return Ok(self); - } - - let identify_regions = self.tcx.sess.opts.debugging_opts.identify_regions; - - // These printouts are concise. They do not contain all the information - // the user might want to diagnose an error, but there is basically no way - // to fit that into a short string. Hence the recommendation to use - // `explain_region()` or `note_and_explain_region()`. - match *region { - ty::ReEarlyBound(ref data) => { - if data.name != kw::Invalid { - p!(write("{}", data.name)); - return Ok(self); - } - } - ty::ReLateBound(_, br) - | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) - | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { - if let ty::BrNamed(_, name) = br { - if name != kw::Invalid && name != kw::UnderscoreLifetime { - p!(write("{}", name)); - return Ok(self); - } - } - - if let Some((region, counter)) = highlight.highlight_bound_region { - if br == region { - p!(write("'{}", counter)); - return Ok(self); - } - } - } - ty::ReScope(scope) if identify_regions => { - match scope.data { - region::ScopeData::Node => p!(write("'{}s", scope.item_local_id().as_usize())), - region::ScopeData::CallSite => { - p!(write("'{}cs", scope.item_local_id().as_usize())) - } - region::ScopeData::Arguments => { - p!(write("'{}as", scope.item_local_id().as_usize())) - } - region::ScopeData::Destruction => { - p!(write("'{}ds", scope.item_local_id().as_usize())) - } - region::ScopeData::Remainder(first_statement_index) => p!(write( - "'{}_{}rs", - scope.item_local_id().as_usize(), - first_statement_index.index() - )), - } - return Ok(self); - } - ty::ReVar(region_vid) if identify_regions => { - p!(write("{:?}", region_vid)); - return Ok(self); - } - ty::ReVar(_) => {} - ty::ReScope(_) | ty::ReErased => {} - ty::ReStatic => { - p!(write("'static")); - return Ok(self); - } - ty::ReEmpty(ty::UniverseIndex::ROOT) => { - p!(write("'<empty>")); - return Ok(self); - } - ty::ReEmpty(ui) => { - p!(write("'<empty:{:?}>", ui)); - return Ok(self); - } - - // The user should never encounter these in unsubstituted form. - ty::ReClosureBound(vid) => { - p!(write("{:?}", vid)); - return Ok(self); - } - } - - p!(write("'_")); - - Ok(self) - } -} - -// HACK(eddyb) limited to `FmtPrinter` because of `binder_depth`, -// `region_index` and `used_region_names`. -impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { - pub fn name_all_regions<T>( - mut self, - value: &ty::Binder<T>, - ) -> Result<(Self, (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)), fmt::Error> - where - T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>, - { - fn name_by_region_index(index: usize) -> Symbol { - match index { - 0 => Symbol::intern("'r"), - 1 => Symbol::intern("'s"), - i => Symbol::intern(&format!("'t{}", i - 2)), - } - } - - // Replace any anonymous late-bound regions with named - // variants, using new unique identifiers, so that we can - // clearly differentiate between named and unnamed regions in - // the output. We'll probably want to tweak this over time to - // decide just how much information to give. - if self.binder_depth == 0 { - self.prepare_late_bound_region_info(value); - } - - let mut empty = true; - let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| { - write!( - cx, - "{}", - if empty { - empty = false; - start - } else { - cont - } - ) - }; - - define_scoped_cx!(self); - - let mut region_index = self.region_index; - let new_value = self.tcx.replace_late_bound_regions(value, |br| { - let _ = start_or_continue(&mut self, "for<", ", "); - let br = match br { - ty::BrNamed(_, name) => { - let _ = write!(self, "{}", name); - br - } - ty::BrAnon(_) | ty::BrEnv => { - let name = loop { - let name = name_by_region_index(region_index); - region_index += 1; - if !self.used_region_names.contains(&name) { - break name; - } - }; - let _ = write!(self, "{}", name); - ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name) - } - }; - self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)) - }); - start_or_continue(&mut self, "", "> ")?; - - self.binder_depth += 1; - self.region_index = region_index; - Ok((self, new_value)) - } - - pub fn pretty_in_binder<T>(self, value: &ty::Binder<T>) -> Result<Self, fmt::Error> - where - T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>, - { - let old_region_index = self.region_index; - let (new, new_value) = self.name_all_regions(value)?; - let mut inner = new_value.0.print(new)?; - inner.region_index = old_region_index; - inner.binder_depth -= 1; - Ok(inner) - } - - fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>) - where - T: TypeFoldable<'tcx>, - { - struct LateBoundRegionNameCollector<'a>(&'a mut FxHashSet<Symbol>); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_> { - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - match *r { - ty::ReLateBound(_, ty::BrNamed(_, name)) => { - self.0.insert(name); - } - _ => {} - } - r.super_visit_with(self) - } - } - - self.used_region_names.clear(); - let mut collector = LateBoundRegionNameCollector(&mut self.used_region_names); - value.visit_with(&mut collector); - self.region_index = 0; - } -} - -impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::Binder<T> -where - T: Print<'tcx, P, Output = P, Error = P::Error> + TypeFoldable<'tcx>, -{ - type Output = P; - type Error = P::Error; - fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { - cx.in_binder(self) - } -} - -impl<'tcx, T, U, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::OutlivesPredicate<T, U> -where - T: Print<'tcx, P, Output = P, Error = P::Error>, - U: Print<'tcx, P, Output = P, Error = P::Error>, -{ - type Output = P; - type Error = P::Error; - fn print(&self, mut cx: P) -> Result<Self::Output, Self::Error> { - define_scoped_cx!(cx); - p!(print(self.0), write(": "), print(self.1)); - Ok(cx) - } -} - -macro_rules! forward_display_to_print { - ($($ty:ty),+) => { - $(impl fmt::Display for $ty { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ty::tls::with(|tcx| { - tcx.lift(self) - .expect("could not lift for printing") - .print(FmtPrinter::new(tcx, f, Namespace::TypeNS))?; - Ok(()) - }) - } - })+ - }; -} - -macro_rules! define_print_and_forward_display { - (($self:ident, $cx:ident): $($ty:ty $print:block)+) => { - $(impl<'tcx, P: PrettyPrinter<'tcx>> Print<'tcx, P> for $ty { - type Output = P; - type Error = fmt::Error; - fn print(&$self, $cx: P) -> Result<Self::Output, Self::Error> { - #[allow(unused_mut)] - let mut $cx = $cx; - define_scoped_cx!($cx); - let _: () = $print; - #[allow(unreachable_code)] - Ok($cx) - } - })+ - - forward_display_to_print!($($ty),+); - }; -} - -// HACK(eddyb) this is separate because `ty::RegionKind` doesn't need lifting. -impl fmt::Display for ty::RegionKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ty::tls::with(|tcx| { - self.print(FmtPrinter::new(tcx, f, Namespace::TypeNS))?; - Ok(()) - }) - } -} - -/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only -/// the trait path. That is, it will print `Trait<U>` instead of -/// `<T as Trait<U>>`. -#[derive(Copy, Clone, TypeFoldable, Lift)] -pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>); - -impl fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl ty::TraitRef<'tcx> { - pub fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> { - TraitRefPrintOnlyTraitPath(self) - } -} - -impl ty::Binder<ty::TraitRef<'tcx>> { - pub fn print_only_trait_path(self) -> ty::Binder<TraitRefPrintOnlyTraitPath<'tcx>> { - self.map_bound(|tr| tr.print_only_trait_path()) - } -} - -forward_display_to_print! { - Ty<'tcx>, - &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, - &'tcx ty::Const<'tcx>, - - // HACK(eddyb) these are exhaustive instead of generic, - // because `for<'tcx>` isn't possible yet. - ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>, - ty::Binder<ty::TraitRef<'tcx>>, - ty::Binder<TraitRefPrintOnlyTraitPath<'tcx>>, - ty::Binder<ty::FnSig<'tcx>>, - ty::Binder<ty::TraitPredicate<'tcx>>, - ty::Binder<ty::SubtypePredicate<'tcx>>, - ty::Binder<ty::ProjectionPredicate<'tcx>>, - ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>, - ty::Binder<ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>>, - - ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>, - ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> -} - -define_print_and_forward_display! { - (self, cx): - - &'tcx ty::List<Ty<'tcx>> { - p!(write("{{")); - let mut tys = self.iter(); - if let Some(&ty) = tys.next() { - p!(print(ty)); - for &ty in tys { - p!(write(", "), print(ty)); - } - } - p!(write("}}")) - } - - ty::TypeAndMut<'tcx> { - p!(write("{}", self.mutbl.prefix_str()), print(self.ty)) - } - - ty::ExistentialTraitRef<'tcx> { - // Use a type that can't appear in defaults of type parameters. - let dummy_self = cx.tcx().mk_ty_infer(ty::FreshTy(0)); - let trait_ref = self.with_self_ty(cx.tcx(), dummy_self); - p!(print(trait_ref.print_only_trait_path())) - } - - ty::ExistentialProjection<'tcx> { - let name = cx.tcx().associated_item(self.item_def_id).ident; - p!(write("{} = ", name), print(self.ty)) - } - - ty::ExistentialPredicate<'tcx> { - match *self { - ty::ExistentialPredicate::Trait(x) => p!(print(x)), - ty::ExistentialPredicate::Projection(x) => p!(print(x)), - ty::ExistentialPredicate::AutoTrait(def_id) => { - p!(print_def_path(def_id, &[])); - } - } - } - - ty::FnSig<'tcx> { - p!(write("{}", self.unsafety.prefix_str())); - - if self.abi != Abi::Rust { - p!(write("extern {} ", self.abi)); - } - - p!(write("fn"), pretty_fn_sig(self.inputs(), self.c_variadic, self.output())); - } - - ty::InferTy { - if cx.tcx().sess.verbose() { - p!(write("{:?}", self)); - return Ok(cx); - } - match *self { - ty::TyVar(_) => p!(write("_")), - ty::IntVar(_) => p!(write("{}", "{integer}")), - ty::FloatVar(_) => p!(write("{}", "{float}")), - ty::FreshTy(v) => p!(write("FreshTy({})", v)), - ty::FreshIntTy(v) => p!(write("FreshIntTy({})", v)), - ty::FreshFloatTy(v) => p!(write("FreshFloatTy({})", v)) - } - } - - ty::TraitRef<'tcx> { - p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path())) - } - - TraitRefPrintOnlyTraitPath<'tcx> { - p!(print_def_path(self.0.def_id, self.0.substs)); - } - - ty::ParamTy { - p!(write("{}", self.name)) - } - - ty::ParamConst { - p!(write("{}", self.name)) - } - - ty::SubtypePredicate<'tcx> { - p!(print(self.a), write(" <: "), print(self.b)) - } - - ty::TraitPredicate<'tcx> { - p!(print(self.trait_ref.self_ty()), write(": "), - print(self.trait_ref.print_only_trait_path())) - } - - ty::ProjectionPredicate<'tcx> { - p!(print(self.projection_ty), write(" == "), print(self.ty)) - } - - ty::ProjectionTy<'tcx> { - p!(print_def_path(self.item_def_id, self.substs)); - } - - ty::ClosureKind { - match *self { - ty::ClosureKind::Fn => p!(write("Fn")), - ty::ClosureKind::FnMut => p!(write("FnMut")), - ty::ClosureKind::FnOnce => p!(write("FnOnce")), - } - } - - ty::Predicate<'tcx> { - match *self { - ty::Predicate::Trait(ref data, constness) => { - if let hir::Constness::Const = constness { - p!(write("const ")); - } - p!(print(data)) - } - ty::Predicate::Subtype(ref predicate) => p!(print(predicate)), - ty::Predicate::RegionOutlives(ref predicate) => p!(print(predicate)), - ty::Predicate::TypeOutlives(ref predicate) => p!(print(predicate)), - ty::Predicate::Projection(ref predicate) => p!(print(predicate)), - ty::Predicate::WellFormed(ty) => p!(print(ty), write(" well-formed")), - ty::Predicate::ObjectSafe(trait_def_id) => { - p!(write("the trait `"), - print_def_path(trait_def_id, &[]), - write("` is object-safe")) - } - ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) => { - p!(write("the closure `"), - print_value_path(closure_def_id, &[]), - write("` implements the trait `{}`", kind)) - } - ty::Predicate::ConstEvaluatable(def_id, substs) => { - p!(write("the constant `"), - print_value_path(def_id, substs), - write("` can be evaluated")) - } - } - } - - GenericArg<'tcx> { - match self.unpack() { - GenericArgKind::Lifetime(lt) => p!(print(lt)), - GenericArgKind::Type(ty) => p!(print(ty)), - GenericArgKind::Const(ct) => p!(print(ct)), - } - } -} diff --git a/src/librustc/ty/query/README.md b/src/librustc/ty/query/README.md deleted file mode 100644 index 4b5e08cecd9..00000000000 --- a/src/librustc/ty/query/README.md +++ /dev/null @@ -1,3 +0,0 @@ -For more information about how the query system works, see the [rustc guide]. - -[rustc guide]: https://rust-lang.github.io/rustc-guide/query.html diff --git a/src/librustc/ty/query/caches.rs b/src/librustc/ty/query/caches.rs deleted file mode 100644 index efc2804bd4d..00000000000 --- a/src/librustc/ty/query/caches.rs +++ /dev/null @@ -1,112 +0,0 @@ -use crate::dep_graph::DepNodeIndex; -use crate::ty::query::config::QueryAccessors; -use crate::ty::query::plumbing::{QueryLookup, QueryState, QueryStateShard}; -use crate::ty::TyCtxt; - -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sharded::Sharded; -use std::default::Default; -use std::hash::Hash; - -pub(crate) trait CacheSelector<K, V> { - type Cache: QueryCache<K, V>; -} - -pub(crate) trait QueryCache<K, V>: Default { - type Sharded: Default; - - /// Checks if the query is already computed and in the cache. - /// It returns the shard index and a lock guard to the shard, - /// which will be used if the query is not in the cache and we need - /// to compute it. - fn lookup<'tcx, R, GetCache, OnHit, OnMiss, Q>( - &self, - state: &'tcx QueryState<'tcx, Q>, - get_cache: GetCache, - key: K, - // `on_hit` can be called while holding a lock to the query state shard. - on_hit: OnHit, - on_miss: OnMiss, - ) -> R - where - Q: QueryAccessors<'tcx>, - GetCache: for<'a> Fn(&'a mut QueryStateShard<'tcx, Q>) -> &'a mut Self::Sharded, - OnHit: FnOnce(&V, DepNodeIndex) -> R, - OnMiss: FnOnce(K, QueryLookup<'tcx, Q>) -> R; - - fn complete( - &self, - tcx: TyCtxt<'tcx>, - lock_sharded_storage: &mut Self::Sharded, - key: K, - value: V, - index: DepNodeIndex, - ); - - fn iter<R, L>( - &self, - shards: &Sharded<L>, - get_shard: impl Fn(&mut L) -> &mut Self::Sharded, - f: impl for<'a> FnOnce(Box<dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)> + 'a>) -> R, - ) -> R; -} - -pub struct DefaultCacheSelector; - -impl<K: Eq + Hash, V: Clone> CacheSelector<K, V> for DefaultCacheSelector { - type Cache = DefaultCache; -} - -#[derive(Default)] -pub struct DefaultCache; - -impl<K: Eq + Hash, V: Clone> QueryCache<K, V> for DefaultCache { - type Sharded = FxHashMap<K, (V, DepNodeIndex)>; - - #[inline(always)] - fn lookup<'tcx, R, GetCache, OnHit, OnMiss, Q>( - &self, - state: &'tcx QueryState<'tcx, Q>, - get_cache: GetCache, - key: K, - on_hit: OnHit, - on_miss: OnMiss, - ) -> R - where - Q: QueryAccessors<'tcx>, - GetCache: for<'a> Fn(&'a mut QueryStateShard<'tcx, Q>) -> &'a mut Self::Sharded, - OnHit: FnOnce(&V, DepNodeIndex) -> R, - OnMiss: FnOnce(K, QueryLookup<'tcx, Q>) -> R, - { - let mut lookup = state.get_lookup(&key); - let lock = &mut *lookup.lock; - - let result = get_cache(lock).raw_entry().from_key_hashed_nocheck(lookup.key_hash, &key); - - if let Some((_, value)) = result { on_hit(&value.0, value.1) } else { on_miss(key, lookup) } - } - - #[inline] - fn complete( - &self, - _: TyCtxt<'tcx>, - lock_sharded_storage: &mut Self::Sharded, - key: K, - value: V, - index: DepNodeIndex, - ) { - lock_sharded_storage.insert(key, (value, index)); - } - - fn iter<R, L>( - &self, - shards: &Sharded<L>, - get_shard: impl Fn(&mut L) -> &mut Self::Sharded, - f: impl for<'a> FnOnce(Box<dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)> + 'a>) -> R, - ) -> R { - let mut shards = shards.lock_shards(); - let mut shards: Vec<_> = shards.iter_mut().map(|shard| get_shard(shard)).collect(); - let results = shards.iter_mut().flat_map(|shard| shard.iter()).map(|(k, v)| (k, &v.0, v.1)); - f(Box::new(results)) - } -} diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs deleted file mode 100644 index e0e1ca374d9..00000000000 --- a/src/librustc/ty/query/config.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::dep_graph::SerializedDepNodeIndex; -use crate::dep_graph::{DepKind, DepNode}; -use crate::ty::query::caches::QueryCache; -use crate::ty::query::plumbing::CycleError; -use crate::ty::query::queries; -use crate::ty::query::{Query, QueryState}; -use crate::ty::TyCtxt; -use rustc_data_structures::profiling::ProfileCategory; -use rustc_hir::def_id::{CrateNum, DefId}; - -use crate::ich::StableHashingContext; -use rustc_data_structures::fingerprint::Fingerprint; -use std::borrow::Cow; -use std::fmt::Debug; -use std::hash::Hash; - -// Query configuration and description traits. - -// FIXME(eddyb) false positive, the lifetime parameter is used for `Key`/`Value`. -#[allow(unused_lifetimes)] -pub trait QueryConfig<'tcx> { - const NAME: &'static str; - const CATEGORY: ProfileCategory; - - type Key: Eq + Hash + Clone + Debug; - type Value: Clone; -} - -pub(crate) trait QueryAccessors<'tcx>: QueryConfig<'tcx> { - const ANON: bool; - const EVAL_ALWAYS: bool; - - type Cache: QueryCache<Self::Key, Self::Value>; - - fn query(key: Self::Key) -> Query<'tcx>; - - // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_state<'a>(tcx: TyCtxt<'tcx>) -> &'a QueryState<'tcx, Self>; - - fn to_dep_node(tcx: TyCtxt<'tcx>, key: &Self::Key) -> DepNode; - - fn dep_kind() -> DepKind; - - // Don't use this method to compute query results, instead use the methods on TyCtxt - fn compute(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value; - - fn hash_result(hcx: &mut StableHashingContext<'_>, result: &Self::Value) - -> Option<Fingerprint>; - - fn handle_cycle_error(tcx: TyCtxt<'tcx>, error: CycleError<'tcx>) -> Self::Value; -} - -pub(crate) trait QueryDescription<'tcx>: QueryAccessors<'tcx> { - fn describe(tcx: TyCtxt<'_>, key: Self::Key) -> Cow<'static, str>; - - #[inline] - fn cache_on_disk(_: TyCtxt<'tcx>, _: Self::Key, _: Option<&Self::Value>) -> bool { - false - } - - fn try_load_from_disk(_: TyCtxt<'tcx>, _: SerializedDepNodeIndex) -> Option<Self::Value> { - bug!("QueryDescription::load_from_disk() called for an unsupported query.") - } -} - -impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M -where - <M as QueryAccessors<'tcx>>::Cache: QueryCache<DefId, <M as QueryConfig<'tcx>>::Value>, -{ - default fn describe(tcx: TyCtxt<'_>, def_id: DefId) -> Cow<'static, str> { - if !tcx.sess.verbose() { - format!("processing `{}`", tcx.def_path_str(def_id)).into() - } else { - let name = ::std::any::type_name::<M>(); - format!("processing {:?} with query `{}`", def_id, name).into() - } - } - - default fn cache_on_disk(_: TyCtxt<'tcx>, _: Self::Key, _: Option<&Self::Value>) -> bool { - false - } - - default fn try_load_from_disk( - _: TyCtxt<'tcx>, - _: SerializedDepNodeIndex, - ) -> Option<Self::Value> { - bug!("QueryDescription::load_from_disk() called for an unsupported query.") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::analysis<'tcx> { - fn describe(_tcx: TyCtxt<'_>, _: CrateNum) -> Cow<'static, str> { - "running analysis passes on this crate".into() - } -} diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs deleted file mode 100644 index 3394fed8402..00000000000 --- a/src/librustc/ty/query/job.rs +++ /dev/null @@ -1,589 +0,0 @@ -use crate::dep_graph::DepKind; -use crate::ty::context::TyCtxt; -use crate::ty::query::plumbing::CycleError; -use crate::ty::query::Query; -use crate::ty::tls; - -use rustc_data_structures::fx::FxHashMap; -use rustc_span::Span; - -use std::convert::TryFrom; -use std::marker::PhantomData; -use std::num::NonZeroU32; - -#[cfg(parallel_compiler)] -use { - parking_lot::{Condvar, Mutex}, - rustc_data_structures::fx::FxHashSet, - rustc_data_structures::stable_hasher::{HashStable, StableHasher}, - rustc_data_structures::sync::Lock, - rustc_data_structures::sync::Lrc, - rustc_data_structures::{jobserver, OnDrop}, - rustc_rayon_core as rayon_core, - rustc_span::DUMMY_SP, - std::iter::FromIterator, - std::{mem, process, thread}, -}; - -/// Represents a span and a query key. -#[derive(Clone, Debug)] -pub struct QueryInfo<'tcx> { - /// The span corresponding to the reason for which this query was required. - pub span: Span, - pub query: Query<'tcx>, -} - -type QueryMap<'tcx> = FxHashMap<QueryJobId, QueryJobInfo<'tcx>>; - -/// A value uniquely identifiying an active query job within a shard in the query cache. -#[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct QueryShardJobId(pub NonZeroU32); - -/// A value uniquely identifiying an active query job. -#[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct QueryJobId { - /// Which job within a shard is this - pub job: QueryShardJobId, - - /// In which shard is this job - pub shard: u16, - - /// What kind of query this job is - pub kind: DepKind, -} - -impl QueryJobId { - pub fn new(job: QueryShardJobId, shard: usize, kind: DepKind) -> Self { - QueryJobId { job, shard: u16::try_from(shard).unwrap(), kind } - } - - fn query<'tcx>(self, map: &QueryMap<'tcx>) -> Query<'tcx> { - map.get(&self).unwrap().info.query.clone() - } - - #[cfg(parallel_compiler)] - fn span(self, map: &QueryMap<'_>) -> Span { - map.get(&self).unwrap().job.span - } - - #[cfg(parallel_compiler)] - fn parent(self, map: &QueryMap<'_>) -> Option<QueryJobId> { - map.get(&self).unwrap().job.parent - } - - #[cfg(parallel_compiler)] - fn latch<'a, 'tcx>(self, map: &'a QueryMap<'tcx>) -> Option<&'a QueryLatch<'tcx>> { - map.get(&self).unwrap().job.latch.as_ref() - } -} - -pub struct QueryJobInfo<'tcx> { - pub info: QueryInfo<'tcx>, - pub job: QueryJob<'tcx>, -} - -/// Represents an active query job. -#[derive(Clone)] -pub struct QueryJob<'tcx> { - pub id: QueryShardJobId, - - /// The span corresponding to the reason for which this query was required. - pub span: Span, - - /// The parent query job which created this job and is implicitly waiting on it. - pub parent: Option<QueryJobId>, - - /// The latch that is used to wait on this job. - #[cfg(parallel_compiler)] - latch: Option<QueryLatch<'tcx>>, - - dummy: PhantomData<QueryLatch<'tcx>>, -} - -impl<'tcx> QueryJob<'tcx> { - /// Creates a new query job. - pub fn new(id: QueryShardJobId, span: Span, parent: Option<QueryJobId>) -> Self { - QueryJob { - id, - span, - parent, - #[cfg(parallel_compiler)] - latch: None, - dummy: PhantomData, - } - } - - #[cfg(parallel_compiler)] - pub(super) fn latch(&mut self, _id: QueryJobId) -> QueryLatch<'tcx> { - if self.latch.is_none() { - self.latch = Some(QueryLatch::new()); - } - self.latch.as_ref().unwrap().clone() - } - - #[cfg(not(parallel_compiler))] - pub(super) fn latch(&mut self, id: QueryJobId) -> QueryLatch<'tcx> { - QueryLatch { id, dummy: PhantomData } - } - - /// Signals to waiters that the query is complete. - /// - /// This does nothing for single threaded rustc, - /// as there are no concurrent jobs which could be waiting on us - pub fn signal_complete(self) { - #[cfg(parallel_compiler)] - self.latch.map(|latch| latch.set()); - } -} - -#[cfg(not(parallel_compiler))] -#[derive(Clone)] -pub(super) struct QueryLatch<'tcx> { - id: QueryJobId, - dummy: PhantomData<&'tcx ()>, -} - -#[cfg(not(parallel_compiler))] -impl<'tcx> QueryLatch<'tcx> { - pub(super) fn find_cycle_in_stack(&self, tcx: TyCtxt<'tcx>, span: Span) -> CycleError<'tcx> { - let query_map = tcx.queries.try_collect_active_jobs().unwrap(); - - // Get the current executing query (waiter) and find the waitee amongst its parents - let mut current_job = tls::with_related_context(tcx, |icx| icx.query); - let mut cycle = Vec::new(); - - while let Some(job) = current_job { - let info = query_map.get(&job).unwrap(); - cycle.push(info.info.clone()); - - if job == self.id { - cycle.reverse(); - - // This is the end of the cycle - // The span entry we included was for the usage - // of the cycle itself, and not part of the cycle - // Replace it with the span which caused the cycle to form - cycle[0].span = span; - // Find out why the cycle itself was used - let usage = info - .job - .parent - .as_ref() - .map(|parent| (info.info.span, parent.query(&query_map))); - return CycleError { usage, cycle }; - } - - current_job = info.job.parent; - } - - panic!("did not find a cycle") - } -} - -#[cfg(parallel_compiler)] -struct QueryWaiter<'tcx> { - query: Option<QueryJobId>, - condvar: Condvar, - span: Span, - cycle: Lock<Option<CycleError<'tcx>>>, -} - -#[cfg(parallel_compiler)] -impl<'tcx> QueryWaiter<'tcx> { - fn notify(&self, registry: &rayon_core::Registry) { - rayon_core::mark_unblocked(registry); - self.condvar.notify_one(); - } -} - -#[cfg(parallel_compiler)] -struct QueryLatchInfo<'tcx> { - complete: bool, - waiters: Vec<Lrc<QueryWaiter<'tcx>>>, -} - -#[cfg(parallel_compiler)] -#[derive(Clone)] -pub(super) struct QueryLatch<'tcx> { - info: Lrc<Mutex<QueryLatchInfo<'tcx>>>, -} - -#[cfg(parallel_compiler)] -impl<'tcx> QueryLatch<'tcx> { - fn new() -> Self { - QueryLatch { - info: Lrc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })), - } - } - - /// Awaits for the query job to complete. - #[cfg(parallel_compiler)] - pub(super) fn wait_on(&self, tcx: TyCtxt<'tcx>, span: Span) -> Result<(), CycleError<'tcx>> { - tls::with_related_context(tcx, move |icx| { - let waiter = Lrc::new(QueryWaiter { - query: icx.query, - span, - cycle: Lock::new(None), - condvar: Condvar::new(), - }); - self.wait_on_inner(&waiter); - // FIXME: Get rid of this lock. We have ownership of the QueryWaiter - // although another thread may still have a Lrc reference so we cannot - // use Lrc::get_mut - let mut cycle = waiter.cycle.lock(); - match cycle.take() { - None => Ok(()), - Some(cycle) => Err(cycle), - } - }) - } - - /// Awaits the caller on this latch by blocking the current thread. - fn wait_on_inner(&self, waiter: &Lrc<QueryWaiter<'tcx>>) { - let mut info = self.info.lock(); - if !info.complete { - // We push the waiter on to the `waiters` list. It can be accessed inside - // the `wait` call below, by 1) the `set` method or 2) by deadlock detection. - // Both of these will remove it from the `waiters` list before resuming - // this thread. - info.waiters.push(waiter.clone()); - - // If this detects a deadlock and the deadlock handler wants to resume this thread - // we have to be in the `wait` call. This is ensured by the deadlock handler - // getting the self.info lock. - rayon_core::mark_blocked(); - jobserver::release_thread(); - waiter.condvar.wait(&mut info); - // Release the lock before we potentially block in `acquire_thread` - mem::drop(info); - jobserver::acquire_thread(); - } - } - - /// Sets the latch and resumes all waiters on it - fn set(&self) { - let mut info = self.info.lock(); - debug_assert!(!info.complete); - info.complete = true; - let registry = rayon_core::Registry::current(); - for waiter in info.waiters.drain(..) { - waiter.notify(®istry); - } - } - - /// Removes a single waiter from the list of waiters. - /// This is used to break query cycles. - fn extract_waiter(&self, waiter: usize) -> Lrc<QueryWaiter<'tcx>> { - let mut info = self.info.lock(); - debug_assert!(!info.complete); - // Remove the waiter from the list of waiters - info.waiters.remove(waiter) - } -} - -/// A resumable waiter of a query. The usize is the index into waiters in the query's latch -#[cfg(parallel_compiler)] -type Waiter = (QueryJobId, usize); - -/// Visits all the non-resumable and resumable waiters of a query. -/// Only waiters in a query are visited. -/// `visit` is called for every waiter and is passed a query waiting on `query_ref` -/// and a span indicating the reason the query waited on `query_ref`. -/// If `visit` returns Some, this function returns. -/// For visits of non-resumable waiters it returns the return value of `visit`. -/// For visits of resumable waiters it returns Some(Some(Waiter)) which has the -/// required information to resume the waiter. -/// If all `visit` calls returns None, this function also returns None. -#[cfg(parallel_compiler)] -fn visit_waiters<'tcx, F>( - query_map: &QueryMap<'tcx>, - query: QueryJobId, - mut visit: F, -) -> Option<Option<Waiter>> -where - F: FnMut(Span, QueryJobId) -> Option<Option<Waiter>>, -{ - // Visit the parent query which is a non-resumable waiter since it's on the same stack - if let Some(parent) = query.parent(query_map) { - if let Some(cycle) = visit(query.span(query_map), parent) { - return Some(cycle); - } - } - - // Visit the explicit waiters which use condvars and are resumable - if let Some(latch) = query.latch(query_map) { - for (i, waiter) in latch.info.lock().waiters.iter().enumerate() { - if let Some(waiter_query) = waiter.query { - if visit(waiter.span, waiter_query).is_some() { - // Return a value which indicates that this waiter can be resumed - return Some(Some((query, i))); - } - } - } - } - - None -} - -/// Look for query cycles by doing a depth first search starting at `query`. -/// `span` is the reason for the `query` to execute. This is initially DUMMY_SP. -/// If a cycle is detected, this initial value is replaced with the span causing -/// the cycle. -#[cfg(parallel_compiler)] -fn cycle_check<'tcx>( - query_map: &QueryMap<'tcx>, - query: QueryJobId, - span: Span, - stack: &mut Vec<(Span, QueryJobId)>, - visited: &mut FxHashSet<QueryJobId>, -) -> Option<Option<Waiter>> { - if !visited.insert(query) { - return if let Some(p) = stack.iter().position(|q| q.1 == query) { - // We detected a query cycle, fix up the initial span and return Some - - // Remove previous stack entries - stack.drain(0..p); - // Replace the span for the first query with the cycle cause - stack[0].0 = span; - Some(None) - } else { - None - }; - } - - // Query marked as visited is added it to the stack - stack.push((span, query)); - - // Visit all the waiters - let r = visit_waiters(query_map, query, |span, successor| { - cycle_check(query_map, successor, span, stack, visited) - }); - - // Remove the entry in our stack if we didn't find a cycle - if r.is_none() { - stack.pop(); - } - - r -} - -/// Finds out if there's a path to the compiler root (aka. code which isn't in a query) -/// from `query` without going through any of the queries in `visited`. -/// This is achieved with a depth first search. -#[cfg(parallel_compiler)] -fn connected_to_root<'tcx>( - query_map: &QueryMap<'tcx>, - query: QueryJobId, - visited: &mut FxHashSet<QueryJobId>, -) -> bool { - // We already visited this or we're deliberately ignoring it - if !visited.insert(query) { - return false; - } - - // This query is connected to the root (it has no query parent), return true - if query.parent(query_map).is_none() { - return true; - } - - visit_waiters(query_map, query, |_, successor| { - connected_to_root(query_map, successor, visited).then_some(None) - }) - .is_some() -} - -// Deterministically pick an query from a list -#[cfg(parallel_compiler)] -fn pick_query<'a, 'tcx, T, F: Fn(&T) -> (Span, QueryJobId)>( - query_map: &QueryMap<'tcx>, - tcx: TyCtxt<'tcx>, - queries: &'a [T], - f: F, -) -> &'a T { - // Deterministically pick an entry point - // FIXME: Sort this instead - let mut hcx = tcx.create_stable_hashing_context(); - queries - .iter() - .min_by_key(|v| { - let (span, query) = f(v); - let mut stable_hasher = StableHasher::new(); - query.query(query_map).hash_stable(&mut hcx, &mut stable_hasher); - // Prefer entry points which have valid spans for nicer error messages - // We add an integer to the tuple ensuring that entry points - // with valid spans are picked first - let span_cmp = if span == DUMMY_SP { 1 } else { 0 }; - (span_cmp, stable_hasher.finish::<u64>()) - }) - .unwrap() -} - -/// Looks for query cycles starting from the last query in `jobs`. -/// If a cycle is found, all queries in the cycle is removed from `jobs` and -/// the function return true. -/// If a cycle was not found, the starting query is removed from `jobs` and -/// the function returns false. -#[cfg(parallel_compiler)] -fn remove_cycle<'tcx>( - query_map: &QueryMap<'tcx>, - jobs: &mut Vec<QueryJobId>, - wakelist: &mut Vec<Lrc<QueryWaiter<'tcx>>>, - tcx: TyCtxt<'tcx>, -) -> bool { - let mut visited = FxHashSet::default(); - let mut stack = Vec::new(); - // Look for a cycle starting with the last query in `jobs` - if let Some(waiter) = - cycle_check(query_map, jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited) - { - // The stack is a vector of pairs of spans and queries; reverse it so that - // the earlier entries require later entries - let (mut spans, queries): (Vec<_>, Vec<_>) = stack.into_iter().rev().unzip(); - - // Shift the spans so that queries are matched with the span for their waitee - spans.rotate_right(1); - - // Zip them back together - let mut stack: Vec<_> = spans.into_iter().zip(queries).collect(); - - // Remove the queries in our cycle from the list of jobs to look at - for r in &stack { - jobs.remove_item(&r.1); - } - - // Find the queries in the cycle which are - // connected to queries outside the cycle - let entry_points = stack - .iter() - .filter_map(|&(span, query)| { - if query.parent(query_map).is_none() { - // This query is connected to the root (it has no query parent) - Some((span, query, None)) - } else { - let mut waiters = Vec::new(); - // Find all the direct waiters who lead to the root - visit_waiters(query_map, query, |span, waiter| { - // Mark all the other queries in the cycle as already visited - let mut visited = FxHashSet::from_iter(stack.iter().map(|q| q.1)); - - if connected_to_root(query_map, waiter, &mut visited) { - waiters.push((span, waiter)); - } - - None - }); - if waiters.is_empty() { - None - } else { - // Deterministically pick one of the waiters to show to the user - let waiter = *pick_query(query_map, tcx, &waiters, |s| *s); - Some((span, query, Some(waiter))) - } - } - }) - .collect::<Vec<(Span, QueryJobId, Option<(Span, QueryJobId)>)>>(); - - // Deterministically pick an entry point - let (_, entry_point, usage) = pick_query(query_map, tcx, &entry_points, |e| (e.0, e.1)); - - // Shift the stack so that our entry point is first - let entry_point_pos = stack.iter().position(|(_, query)| query == entry_point); - if let Some(pos) = entry_point_pos { - stack.rotate_left(pos); - } - - let usage = usage.as_ref().map(|(span, query)| (*span, query.query(query_map))); - - // Create the cycle error - let error = CycleError { - usage, - cycle: stack - .iter() - .map(|&(s, ref q)| QueryInfo { span: s, query: q.query(query_map) }) - .collect(), - }; - - // We unwrap `waiter` here since there must always be one - // edge which is resumeable / waited using a query latch - let (waitee_query, waiter_idx) = waiter.unwrap(); - - // Extract the waiter we want to resume - let waiter = waitee_query.latch(query_map).unwrap().extract_waiter(waiter_idx); - - // Set the cycle error so it will be picked up when resumed - *waiter.cycle.lock() = Some(error); - - // Put the waiter on the list of things to resume - wakelist.push(waiter); - - true - } else { - false - } -} - -/// Creates a new thread and forwards information in thread locals to it. -/// The new thread runs the deadlock handler. -/// Must only be called when a deadlock is about to happen. -#[cfg(parallel_compiler)] -pub unsafe fn handle_deadlock() { - let registry = rayon_core::Registry::current(); - - let gcx_ptr = tls::GCX_PTR.with(|gcx_ptr| gcx_ptr as *const _); - let gcx_ptr = &*gcx_ptr; - - let rustc_span_globals = - rustc_span::GLOBALS.with(|rustc_span_globals| rustc_span_globals as *const _); - let rustc_span_globals = &*rustc_span_globals; - let syntax_globals = syntax::attr::GLOBALS.with(|syntax_globals| syntax_globals as *const _); - let syntax_globals = &*syntax_globals; - thread::spawn(move || { - tls::GCX_PTR.set(gcx_ptr, || { - syntax::attr::GLOBALS.set(syntax_globals, || { - rustc_span::GLOBALS - .set(rustc_span_globals, || tls::with_global(|tcx| deadlock(tcx, ®istry))) - }); - }) - }); -} - -/// Detects query cycles by using depth first search over all active query jobs. -/// If a query cycle is found it will break the cycle by finding an edge which -/// uses a query latch and then resuming that waiter. -/// There may be multiple cycles involved in a deadlock, so this searches -/// all active queries for cycles before finally resuming all the waiters at once. -#[cfg(parallel_compiler)] -fn deadlock(tcx: TyCtxt<'_>, registry: &rayon_core::Registry) { - let on_panic = OnDrop(|| { - eprintln!("deadlock handler panicked, aborting process"); - process::abort(); - }); - - let mut wakelist = Vec::new(); - let query_map = tcx.queries.try_collect_active_jobs().unwrap(); - let mut jobs: Vec<QueryJobId> = query_map.keys().cloned().collect(); - - let mut found_cycle = false; - - while jobs.len() > 0 { - if remove_cycle(&query_map, &mut jobs, &mut wakelist, tcx) { - found_cycle = true; - } - } - - // Check that a cycle was found. It is possible for a deadlock to occur without - // a query cycle if a query which can be waited on uses Rayon to do multithreading - // internally. Such a query (X) may be executing on 2 threads (A and B) and A may - // wait using Rayon on B. Rayon may then switch to executing another query (Y) - // which in turn will wait on X causing a deadlock. We have a false dependency from - // X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here - // only considers the true dependency and won't detect a cycle. - assert!(found_cycle); - - // FIXME: Ensure this won't cause a deadlock before we return - for waiter in wakelist.into_iter() { - waiter.notify(registry); - } - - on_panic.disable(); -} diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs deleted file mode 100644 index 09fb307a1ce..00000000000 --- a/src/librustc/ty/query/keys.rs +++ /dev/null @@ -1,287 +0,0 @@ -//! Defines the set of legal keys that can be used in queries. - -use crate::infer::canonical::Canonical; -use crate::mir; -use crate::traits; -use crate::ty::fast_reject::SimplifiedType; -use crate::ty::query::caches::DefaultCacheSelector; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, Ty, TyCtxt}; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; -use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; - -/// The `Key` trait controls what types can legally be used as the key -/// for a query. -pub trait Key { - type CacheSelector; - - /// Given an instance of this key, what crate is it referring to? - /// This is used to find the provider. - fn query_crate(&self) -> CrateNum; - - /// In the event that a cycle occurs, if no explicit span has been - /// given for a query with key `self`, what span should we use? - fn default_span(&self, tcx: TyCtxt<'_>) -> Span; -} - -impl<'tcx> Key for ty::InstanceDef<'tcx> { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - tcx.def_span(self.def_id()) - } -} - -impl<'tcx> Key for ty::Instance<'tcx> { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - tcx.def_span(self.def_id()) - } -} - -impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.instance.query_crate() - } - - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - self.instance.default_span(tcx) - } -} - -impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { - DUMMY_SP - } -} - -impl Key for CrateNum { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - *self - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { - DUMMY_SP - } -} - -impl Key for DefIndex { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { - DUMMY_SP - } -} - -impl Key for DefId { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.krate - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - tcx.def_span(*self) - } -} - -impl Key for (DefId, DefId) { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.0.krate - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - self.1.default_span(tcx) - } -} - -impl Key for (CrateNum, DefId) { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.0 - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - self.1.default_span(tcx) - } -} - -impl Key for (DefId, SimplifiedType) { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.0.krate - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - self.0.default_span(tcx) - } -} - -impl<'tcx> Key for SubstsRef<'tcx> { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { - DUMMY_SP - } -} - -impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.0.krate - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - self.0.default_span(tcx) - } -} - -impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.1.def_id().krate - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - tcx.def_span(self.1.def_id()) - } -} - -impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { - DUMMY_SP - } -} - -impl<'tcx> Key for ty::PolyTraitRef<'tcx> { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.def_id().krate - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - tcx.def_span(self.def_id()) - } -} - -impl<'tcx> Key for &'tcx ty::Const<'tcx> { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { - DUMMY_SP - } -} - -impl<'tcx> Key for Ty<'tcx> { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { - DUMMY_SP - } -} - -impl<'tcx> Key for ty::ParamEnv<'tcx> { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { - DUMMY_SP - } -} - -impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.value.query_crate() - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - self.value.default_span(tcx) - } -} - -impl<'tcx> Key for traits::Environment<'tcx> { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { - DUMMY_SP - } -} - -impl Key for Symbol { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { - DUMMY_SP - } -} - -/// Canonical query goals correspond to abstract trait operations that -/// are not tied to any crate in particular. -impl<'tcx, T> Key for Canonical<'tcx, T> { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { - DUMMY_SP - } -} - -impl Key for (Symbol, u32, u32) { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - LOCAL_CRATE - } - - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { - DUMMY_SP - } -} diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs deleted file mode 100644 index 381a7b1f03f..00000000000 --- a/src/librustc/ty/query/mod.rs +++ /dev/null @@ -1,112 +0,0 @@ -use crate::dep_graph::{self, DepConstructor, DepNode}; -use crate::hir::exports::Export; -use crate::infer::canonical::{self, Canonical}; -use crate::lint::LintLevelMap; -use crate::middle::codegen_fn_attrs::CodegenFnAttrs; -use crate::middle::cstore::{CrateSource, DepKind, NativeLibraryKind}; -use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLibrary}; -use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; -use crate::middle::lang_items::{LangItem, LanguageItems}; -use crate::middle::lib_features::LibFeatures; -use crate::middle::privacy::AccessLevels; -use crate::middle::region; -use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes}; -use crate::middle::stability::{self, DeprecationEntry}; -use crate::mir; -use crate::mir::interpret::GlobalId; -use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult, ConstValue}; -use crate::mir::interpret::{LitToConstError, LitToConstInput}; -use crate::mir::mono::CodegenUnit; -use crate::session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; -use crate::session::CrateDisambiguator; -use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution, -}; -use crate::traits::query::{ - DropckOutlivesResult, DtorckConstraint, MethodAutoderefStepsResult, NormalizationResult, - OutlivesBound, -}; -use crate::traits::specialization_graph; -use crate::traits::Clauses; -use crate::traits::{self, Vtable}; -use crate::ty::steal::Steal; -use crate::ty::subst::SubstsRef; -use crate::ty::util::AlwaysRequiresDrop; -use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; -use crate::util::common::ErrorReported; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_data_structures::profiling::ProfileCategory::*; -use rustc_data_structures::stable_hasher::StableVec; -use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::Lrc; -use rustc_hir as hir; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex}; -use rustc_hir::{Crate, HirIdSet, ItemLocalId, TraitCandidate}; -use rustc_index::vec::IndexVec; -use rustc_target::spec::PanicStrategy; - -use rustc_attr as attr; -use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; -use std::borrow::Cow; -use std::convert::TryFrom; -use std::ops::Deref; -use std::sync::Arc; -use syntax::ast; - -#[macro_use] -mod plumbing; -use self::plumbing::*; -pub use self::plumbing::{force_from_dep_node, CycleError}; - -mod stats; -pub use self::stats::print_stats; - -mod job; -#[cfg(parallel_compiler)] -pub use self::job::handle_deadlock; -use self::job::QueryJobInfo; -pub use self::job::{QueryInfo, QueryJob, QueryJobId}; - -mod keys; -use self::keys::Key; - -mod values; -use self::values::Value; - -mod caches; -use self::caches::CacheSelector; - -mod config; -use self::config::QueryAccessors; -pub use self::config::QueryConfig; -pub(crate) use self::config::QueryDescription; - -mod on_disk_cache; -pub use self::on_disk_cache::OnDiskCache; - -mod profiling_support; -pub use self::profiling_support::{IntoSelfProfilingString, QueryKeyStringBuilder}; - -// Each of these queries corresponds to a function pointer field in the -// `Providers` struct for requesting a value of that type, and a method -// on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way -// which memoizes and does dep-graph tracking, wrapping around the actual -// `Providers` that the driver creates (using several `rustc_*` crates). -// -// The result type of each query must implement `Clone`, and additionally -// `ty::query::values::Value`, which produces an appropriate placeholder -// (error) value if the query resulted in a query cycle. -// Queries marked with `fatal_cycle` do not need the latter implementation, -// as they will raise an fatal error on query cycles instead. - -rustc_query_append! { [define_queries!][ <'tcx> - Other { - /// Runs analysis passes on the crate. - [eval_always] fn analysis: Analysis(CrateNum) -> Result<(), ErrorReported>, - }, -]} diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs deleted file mode 100644 index f96bf6c110c..00000000000 --- a/src/librustc/ty/query/on_disk_cache.rs +++ /dev/null @@ -1,1057 +0,0 @@ -use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; -use crate::hir::map::definitions::DefPathHash; -use crate::ich::{CachingSourceMapView, Fingerprint}; -use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; -use crate::mir::{self, interpret}; -use crate::session::{CrateDisambiguator, Session}; -use crate::ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; -use crate::ty::context::TyCtxt; -use crate::ty::{self, Ty}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, Once}; -use rustc_data_structures::thin_vec::ThinVec; -use rustc_errors::Diagnostic; -use rustc_hir as hir; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_serialize::{ - opaque, Decodable, Decoder, Encodable, Encoder, SpecializedDecoder, SpecializedEncoder, - UseSpecializedDecodable, UseSpecializedEncodable, -}; -use rustc_span::hygiene::{ExpnId, SyntaxContext}; -use rustc_span::source_map::{SourceMap, StableSourceFileId}; -use rustc_span::{BytePos, SourceFile, Span, DUMMY_SP}; -use std::mem; -use syntax::ast::Ident; - -const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; - -const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; -const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; - -const TAG_NO_EXPN_DATA: u8 = 0; -const TAG_EXPN_DATA_SHORTHAND: u8 = 1; -const TAG_EXPN_DATA_INLINE: u8 = 2; - -const TAG_VALID_SPAN: u8 = 0; -const TAG_INVALID_SPAN: u8 = 1; - -/// Provides an interface to incremental compilation data cached from the -/// previous compilation session. This data will eventually include the results -/// of a few selected queries (like `typeck_tables_of` and `mir_optimized`) and -/// any diagnostics that have been emitted during a query. -pub struct OnDiskCache<'sess> { - // The complete cache data in serialized form. - serialized_data: Vec<u8>, - - // Collects all `Diagnostic`s emitted during the current compilation - // session. - current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>, - - prev_cnums: Vec<(u32, String, CrateDisambiguator)>, - cnum_map: Once<IndexVec<CrateNum, Option<CrateNum>>>, - - source_map: &'sess SourceMap, - file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>, - - // Caches that are populated lazily during decoding. - file_index_to_file: Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>, - synthetic_syntax_contexts: Lock<FxHashMap<AbsoluteBytePos, SyntaxContext>>, - - // A map from dep-node to the position of the cached query result in - // `serialized_data`. - query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>, - - // A map from dep-node to the position of any associated diagnostics in - // `serialized_data`. - prev_diagnostics_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>, - - alloc_decoding_state: AllocDecodingState, -} - -// This type is used only for (de-)serialization. -#[derive(RustcEncodable, RustcDecodable)] -struct Footer { - file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>, - prev_cnums: Vec<(u32, String, CrateDisambiguator)>, - query_result_index: EncodedQueryResultIndex, - diagnostics_index: EncodedQueryResultIndex, - // The location of all allocations. - interpret_alloc_index: Vec<u32>, -} - -type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; -type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; -type EncodedDiagnostics = Vec<Diagnostic>; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -struct SourceFileIndex(u32); - -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, RustcEncodable, RustcDecodable)] -struct AbsoluteBytePos(u32); - -impl AbsoluteBytePos { - fn new(pos: usize) -> AbsoluteBytePos { - debug_assert!(pos <= ::std::u32::MAX as usize); - AbsoluteBytePos(pos as u32) - } - - fn to_usize(self) -> usize { - self.0 as usize - } -} - -impl<'sess> OnDiskCache<'sess> { - /// Creates a new `OnDiskCache` instance from the serialized data in `data`. - pub fn new(sess: &'sess Session, data: Vec<u8>, start_pos: usize) -> Self { - debug_assert!(sess.opts.incremental.is_some()); - - // Wrap in a scope so we can borrow `data`. - let footer: Footer = { - let mut decoder = opaque::Decoder::new(&data[..], start_pos); - - // Decode the *position* of the footer, which can be found in the - // last 8 bytes of the file. - decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE); - let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder) - .expect("error while trying to decode footer position") - .0 as usize; - - // Decode the file footer, which contains all the lookup tables, etc. - decoder.set_position(footer_pos); - decode_tagged(&mut decoder, TAG_FILE_FOOTER) - .expect("error while trying to decode footer position") - }; - - Self { - serialized_data: data, - file_index_to_stable_id: footer.file_index_to_stable_id, - file_index_to_file: Default::default(), - prev_cnums: footer.prev_cnums, - cnum_map: Once::new(), - source_map: sess.source_map(), - current_diagnostics: Default::default(), - query_result_index: footer.query_result_index.into_iter().collect(), - prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(), - synthetic_syntax_contexts: Default::default(), - alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index), - } - } - - pub fn new_empty(source_map: &'sess SourceMap) -> Self { - Self { - serialized_data: Vec::new(), - file_index_to_stable_id: Default::default(), - file_index_to_file: Default::default(), - prev_cnums: vec![], - cnum_map: Once::new(), - source_map, - current_diagnostics: Default::default(), - query_result_index: Default::default(), - prev_diagnostics_index: Default::default(), - synthetic_syntax_contexts: Default::default(), - alloc_decoding_state: AllocDecodingState::new(Vec::new()), - } - } - - pub fn serialize<'tcx, E>(&self, tcx: TyCtxt<'tcx>, encoder: &mut E) -> Result<(), E::Error> - where - E: TyEncoder, - { - // Serializing the `DepGraph` should not modify it. - tcx.dep_graph.with_ignore(|| { - // Allocate `SourceFileIndex`es. - let (file_to_file_index, file_index_to_stable_id) = { - let files = tcx.sess.source_map().files(); - let mut file_to_file_index = - FxHashMap::with_capacity_and_hasher(files.len(), Default::default()); - let mut file_index_to_stable_id = - FxHashMap::with_capacity_and_hasher(files.len(), Default::default()); - - for (index, file) in files.iter().enumerate() { - let index = SourceFileIndex(index as u32); - let file_ptr: *const SourceFile = &**file as *const _; - file_to_file_index.insert(file_ptr, index); - file_index_to_stable_id.insert(index, StableSourceFileId::new(&file)); - } - - (file_to_file_index, file_index_to_stable_id) - }; - - let mut encoder = CacheEncoder { - tcx, - encoder, - type_shorthands: Default::default(), - predicate_shorthands: Default::default(), - expn_data_shorthands: Default::default(), - interpret_allocs: Default::default(), - interpret_allocs_inverse: Vec::new(), - source_map: CachingSourceMapView::new(tcx.sess.source_map()), - file_to_file_index, - }; - - // Load everything into memory so we can write it out to the on-disk - // cache. The vast majority of cacheable query results should already - // be in memory, so this should be a cheap operation. - tcx.dep_graph.exec_cache_promotions(tcx); - - // Encode query results. - let mut query_result_index = EncodedQueryResultIndex::new(); - - tcx.sess.time("encode_query_results", || { - let enc = &mut encoder; - let qri = &mut query_result_index; - - macro_rules! encode_queries { - ($($query:ident,)*) => { - $( - encode_query_results::<ty::query::queries::$query<'_>, _>( - tcx, - enc, - qri - )?; - )* - } - } - - rustc_cached_queries!(encode_queries!); - - Ok(()) - })?; - - // Encode diagnostics. - let diagnostics_index: EncodedDiagnosticsIndex = self - .current_diagnostics - .borrow() - .iter() - .map(|(dep_node_index, diagnostics)| { - let pos = AbsoluteBytePos::new(encoder.position()); - // Let's make sure we get the expected type here. - let diagnostics: &EncodedDiagnostics = diagnostics; - let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index()); - encoder.encode_tagged(dep_node_index, diagnostics)?; - - Ok((dep_node_index, pos)) - }) - .collect::<Result<_, _>>()?; - - let interpret_alloc_index = { - let mut interpret_alloc_index = Vec::new(); - let mut n = 0; - loop { - let new_n = encoder.interpret_allocs_inverse.len(); - // If we have found new IDs, serialize those too. - if n == new_n { - // Otherwise, abort. - break; - } - interpret_alloc_index.reserve(new_n - n); - for idx in n..new_n { - let id = encoder.interpret_allocs_inverse[idx]; - let pos = encoder.position() as u32; - interpret_alloc_index.push(pos); - interpret::specialized_encode_alloc_id(&mut encoder, tcx, id)?; - } - n = new_n; - } - interpret_alloc_index - }; - - let sorted_cnums = sorted_cnums_including_local_crate(tcx); - let prev_cnums: Vec<_> = sorted_cnums - .iter() - .map(|&cnum| { - let crate_name = tcx.original_crate_name(cnum).to_string(); - let crate_disambiguator = tcx.crate_disambiguator(cnum); - (cnum.as_u32(), crate_name, crate_disambiguator) - }) - .collect(); - - // Encode the file footer. - let footer_pos = encoder.position() as u64; - encoder.encode_tagged( - TAG_FILE_FOOTER, - &Footer { - file_index_to_stable_id, - prev_cnums, - query_result_index, - diagnostics_index, - interpret_alloc_index, - }, - )?; - - // Encode the position of the footer as the last 8 bytes of the - // file so we know where to look for it. - IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?; - - // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address - // of the footer must be the last thing in the data stream. - - return Ok(()); - - fn sorted_cnums_including_local_crate(tcx: TyCtxt<'_>) -> Vec<CrateNum> { - let mut cnums = vec![LOCAL_CRATE]; - cnums.extend_from_slice(&tcx.crates()[..]); - cnums.sort_unstable(); - // Just to be sure... - cnums.dedup(); - cnums - } - }) - } - - /// Loads a diagnostic emitted during the previous compilation session. - pub fn load_diagnostics( - &self, - tcx: TyCtxt<'_>, - dep_node_index: SerializedDepNodeIndex, - ) -> Vec<Diagnostic> { - let diagnostics: Option<EncodedDiagnostics> = - self.load_indexed(tcx, dep_node_index, &self.prev_diagnostics_index, "diagnostics"); - - diagnostics.unwrap_or_default() - } - - /// Stores a diagnostic emitted during the current compilation session. - /// Anything stored like this will be available via `load_diagnostics` in - /// the next compilation session. - #[inline(never)] - #[cold] - pub fn store_diagnostics( - &self, - dep_node_index: DepNodeIndex, - diagnostics: ThinVec<Diagnostic>, - ) { - let mut current_diagnostics = self.current_diagnostics.borrow_mut(); - let prev = current_diagnostics.insert(dep_node_index, diagnostics.into()); - debug_assert!(prev.is_none()); - } - - /// Returns the cached query result if there is something in the cache for - /// the given `SerializedDepNodeIndex`; otherwise returns `None`. - pub fn try_load_query_result<T>( - &self, - tcx: TyCtxt<'_>, - dep_node_index: SerializedDepNodeIndex, - ) -> Option<T> - where - T: Decodable, - { - self.load_indexed(tcx, dep_node_index, &self.query_result_index, "query result") - } - - /// Stores a diagnostic emitted during computation of an anonymous query. - /// Since many anonymous queries can share the same `DepNode`, we aggregate - /// them -- as opposed to regular queries where we assume that there is a - /// 1:1 relationship between query-key and `DepNode`. - #[inline(never)] - #[cold] - pub fn store_diagnostics_for_anon_node( - &self, - dep_node_index: DepNodeIndex, - diagnostics: ThinVec<Diagnostic>, - ) { - let mut current_diagnostics = self.current_diagnostics.borrow_mut(); - - let x = current_diagnostics.entry(dep_node_index).or_insert(Vec::new()); - - x.extend(Into::<Vec<_>>::into(diagnostics)); - } - - fn load_indexed<'tcx, T>( - &self, - tcx: TyCtxt<'tcx>, - dep_node_index: SerializedDepNodeIndex, - index: &FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>, - debug_tag: &'static str, - ) -> Option<T> - where - T: Decodable, - { - let pos = index.get(&dep_node_index).cloned()?; - - // Initialize `cnum_map` using the value from the thread that finishes the closure first. - self.cnum_map.init_nonlocking_same(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..])); - - let mut decoder = CacheDecoder { - tcx, - opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), - source_map: self.source_map, - cnum_map: self.cnum_map.get(), - synthetic_syntax_contexts: &self.synthetic_syntax_contexts, - file_index_to_file: &self.file_index_to_file, - file_index_to_stable_id: &self.file_index_to_stable_id, - alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(), - }; - - match decode_tagged(&mut decoder, dep_node_index) { - Ok(v) => Some(v), - Err(e) => bug!("could not decode cached {}: {}", debug_tag, e), - } - } - - // This function builds mapping from previous-session-`CrateNum` to - // current-session-`CrateNum`. There might be `CrateNum`s from the previous - // `Session` that don't occur in the current one. For these, the mapping - // maps to None. - fn compute_cnum_map( - tcx: TyCtxt<'_>, - prev_cnums: &[(u32, String, CrateDisambiguator)], - ) -> IndexVec<CrateNum, Option<CrateNum>> { - tcx.dep_graph.with_ignore(|| { - let current_cnums = tcx - .all_crate_nums(LOCAL_CRATE) - .iter() - .map(|&cnum| { - let crate_name = tcx.original_crate_name(cnum).to_string(); - let crate_disambiguator = tcx.crate_disambiguator(cnum); - ((crate_name, crate_disambiguator), cnum) - }) - .collect::<FxHashMap<_, _>>(); - - let map_size = prev_cnums.iter().map(|&(cnum, ..)| cnum).max().unwrap_or(0) + 1; - let mut map = IndexVec::from_elem_n(None, map_size as usize); - - for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums { - let key = (crate_name.clone(), crate_disambiguator); - map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&key).cloned(); - } - - map[LOCAL_CRATE] = Some(LOCAL_CRATE); - map - }) - } -} - -//- DECODING ------------------------------------------------------------------- - -/// A decoder that can read fro the incr. comp. cache. It is similar to the one -/// we use for crate metadata decoding in that it can rebase spans and eventually -/// will also handle things that contain `Ty` instances. -struct CacheDecoder<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - opaque: opaque::Decoder<'a>, - source_map: &'a SourceMap, - cnum_map: &'a IndexVec<CrateNum, Option<CrateNum>>, - synthetic_syntax_contexts: &'a Lock<FxHashMap<AbsoluteBytePos, SyntaxContext>>, - file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>, - file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, StableSourceFileId>, - alloc_decoding_session: AllocDecodingSession<'a>, -} - -impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { - fn file_index_to_file(&self, index: SourceFileIndex) -> Lrc<SourceFile> { - let CacheDecoder { - ref file_index_to_file, - ref file_index_to_stable_id, - ref source_map, - .. - } = *self; - - file_index_to_file - .borrow_mut() - .entry(index) - .or_insert_with(|| { - let stable_id = file_index_to_stable_id[&index]; - source_map - .source_file_by_stable_id(stable_id) - .expect("failed to lookup `SourceFile` in new context") - }) - .clone() - } -} - -trait DecoderWithPosition: Decoder { - fn position(&self) -> usize; -} - -impl<'a> DecoderWithPosition for opaque::Decoder<'a> { - fn position(&self) -> usize { - self.position() - } -} - -impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> { - fn position(&self) -> usize { - self.opaque.position() - } -} - -// Decodes something that was encoded with `encode_tagged()` and verify that the -// tag matches and the correct amount of bytes was read. -fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error> -where - T: Decodable + Eq + ::std::fmt::Debug, - V: Decodable, - D: DecoderWithPosition, -{ - let start_pos = decoder.position(); - - let actual_tag = T::decode(decoder)?; - assert_eq!(actual_tag, expected_tag); - let value = V::decode(decoder)?; - let end_pos = decoder.position(); - - let expected_len: u64 = Decodable::decode(decoder)?; - assert_eq!((end_pos - start_pos) as u64, expected_len); - - Ok(value) -} - -impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { - #[inline] - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - #[inline] - fn position(&self) -> usize { - self.opaque.position() - } - - #[inline] - fn peek_byte(&self) -> u8 { - self.opaque.data[self.opaque.position()] - } - - fn cached_ty_for_shorthand<F>( - &mut self, - shorthand: usize, - or_insert_with: F, - ) -> Result<Ty<'tcx>, Self::Error> - where - F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>, - { - let tcx = self.tcx(); - - let cache_key = - ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand }; - - if let Some(&ty) = tcx.rcache.borrow().get(&cache_key) { - return Ok(ty); - } - - let ty = or_insert_with(self)?; - // This may overwrite the entry, but it should overwrite with the same value. - tcx.rcache.borrow_mut().insert_same(cache_key, ty); - Ok(ty) - } - - fn with_position<F, R>(&mut self, pos: usize, f: F) -> R - where - F: FnOnce(&mut Self) -> R, - { - debug_assert!(pos < self.opaque.data.len()); - - let new_opaque = opaque::Decoder::new(self.opaque.data, pos); - let old_opaque = mem::replace(&mut self.opaque, new_opaque); - let r = f(self); - self.opaque = old_opaque; - r - } - - fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum { - self.cnum_map[cnum].unwrap_or_else(|| bug!("could not find new `CrateNum` for {:?}", cnum)) - } -} - -implement_ty_decoder!(CacheDecoder<'a, 'tcx>); - -impl<'a, 'tcx> SpecializedDecoder<interpret::AllocId> for CacheDecoder<'a, 'tcx> { - fn specialized_decode(&mut self) -> Result<interpret::AllocId, Self::Error> { - let alloc_decoding_session = self.alloc_decoding_session; - alloc_decoding_session.decode_alloc_id(self) - } -} - -impl<'a, 'tcx> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx> { - fn specialized_decode(&mut self) -> Result<Span, Self::Error> { - let tag: u8 = Decodable::decode(self)?; - - if tag == TAG_INVALID_SPAN { - return Ok(DUMMY_SP); - } else { - debug_assert_eq!(tag, TAG_VALID_SPAN); - } - - let file_lo_index = SourceFileIndex::decode(self)?; - let line_lo = usize::decode(self)?; - let col_lo = BytePos::decode(self)?; - let len = BytePos::decode(self)?; - - let file_lo = self.file_index_to_file(file_lo_index); - let lo = file_lo.lines[line_lo - 1] + col_lo; - let hi = lo + len; - - let expn_data_tag = u8::decode(self)?; - - // FIXME(mw): This method does not restore `ExpnData::parent` or - // `SyntaxContextData::prev_ctxt` or `SyntaxContextData::opaque`. These things - // don't seem to be used after HIR lowering, so everything should be fine - // until we want incremental compilation to serialize Spans that we need - // full hygiene information for. - let location = || Span::with_root_ctxt(lo, hi); - let recover_from_expn_data = |this: &Self, expn_data, transparency, pos| { - let span = location().fresh_expansion_with_transparency(expn_data, transparency); - this.synthetic_syntax_contexts.borrow_mut().insert(pos, span.ctxt()); - span - }; - Ok(match expn_data_tag { - TAG_NO_EXPN_DATA => location(), - TAG_EXPN_DATA_INLINE => { - let (expn_data, transparency) = Decodable::decode(self)?; - recover_from_expn_data( - self, - expn_data, - transparency, - AbsoluteBytePos::new(self.opaque.position()), - ) - } - TAG_EXPN_DATA_SHORTHAND => { - let pos = AbsoluteBytePos::decode(self)?; - let cached_ctxt = self.synthetic_syntax_contexts.borrow().get(&pos).cloned(); - if let Some(ctxt) = cached_ctxt { - Span::new(lo, hi, ctxt) - } else { - let (expn_data, transparency) = - self.with_position(pos.to_usize(), |this| Decodable::decode(this))?; - recover_from_expn_data(self, expn_data, transparency, pos) - } - } - _ => unreachable!(), - }) - } -} - -impl<'a, 'tcx> SpecializedDecoder<Ident> for CacheDecoder<'a, 'tcx> { - fn specialized_decode(&mut self) -> Result<Ident, Self::Error> { - // FIXME: Handle hygiene in incremental - bug!("Trying to decode Ident for incremental"); - } -} - -// This impl makes sure that we get a runtime error when we try decode a -// `DefIndex` that is not contained in a `DefId`. Such a case would be problematic -// because we would not know how to transform the `DefIndex` to the current -// context. -impl<'a, 'tcx> SpecializedDecoder<DefIndex> for CacheDecoder<'a, 'tcx> { - fn specialized_decode(&mut self) -> Result<DefIndex, Self::Error> { - bug!("trying to decode `DefIndex` outside the context of a `DefId`") - } -} - -// Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two -// compilation sessions. We use the `DefPathHash`, which is stable across -// sessions, to map the old `DefId` to the new one. -impl<'a, 'tcx> SpecializedDecoder<DefId> for CacheDecoder<'a, 'tcx> { - #[inline] - fn specialized_decode(&mut self) -> Result<DefId, Self::Error> { - // Load the `DefPathHash` which is was we encoded the `DefId` as. - let def_path_hash = DefPathHash::decode(self)?; - - // Using the `DefPathHash`, we can lookup the new `DefId`. - Ok(self.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash]) - } -} - -impl<'a, 'tcx> SpecializedDecoder<LocalDefId> for CacheDecoder<'a, 'tcx> { - #[inline] - fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> { - Ok(LocalDefId::from_def_id(DefId::decode(self)?)) - } -} - -impl<'a, 'tcx> SpecializedDecoder<hir::HirId> for CacheDecoder<'a, 'tcx> { - fn specialized_decode(&mut self) -> Result<hir::HirId, Self::Error> { - // Load the `DefPathHash` which is what we encoded the `DefIndex` as. - let def_path_hash = DefPathHash::decode(self)?; - - // Use the `DefPathHash` to map to the current `DefId`. - let def_id = self.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash]; - - debug_assert!(def_id.is_local()); - - // The `ItemLocalId` needs no remapping. - let local_id = hir::ItemLocalId::decode(self)?; - - // Reconstruct the `HirId` and look up the corresponding `NodeId` in the - // context of the current session. - Ok(hir::HirId { owner: def_id.index, local_id }) - } -} - -impl<'a, 'tcx> SpecializedDecoder<Fingerprint> for CacheDecoder<'a, 'tcx> { - fn specialized_decode(&mut self) -> Result<Fingerprint, Self::Error> { - Fingerprint::decode_opaque(&mut self.opaque) - } -} - -impl<'a, 'tcx, T: Decodable> SpecializedDecoder<mir::ClearCrossCrate<T>> - for CacheDecoder<'a, 'tcx> -{ - #[inline] - fn specialized_decode(&mut self) -> Result<mir::ClearCrossCrate<T>, Self::Error> { - let discr = u8::decode(self)?; - - match discr { - TAG_CLEAR_CROSS_CRATE_CLEAR => Ok(mir::ClearCrossCrate::Clear), - TAG_CLEAR_CROSS_CRATE_SET => { - let val = T::decode(self)?; - Ok(mir::ClearCrossCrate::Set(val)) - } - _ => unreachable!(), - } - } -} - -//- ENCODING ------------------------------------------------------------------- - -/// An encoder that can write the incr. comp. cache. -struct CacheEncoder<'a, 'tcx, E: ty_codec::TyEncoder> { - tcx: TyCtxt<'tcx>, - encoder: &'a mut E, - type_shorthands: FxHashMap<Ty<'tcx>, usize>, - predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>, - expn_data_shorthands: FxHashMap<ExpnId, AbsoluteBytePos>, - interpret_allocs: FxHashMap<interpret::AllocId, usize>, - interpret_allocs_inverse: Vec<interpret::AllocId>, - source_map: CachingSourceMapView<'tcx>, - file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>, -} - -impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex { - self.file_to_file_index[&(&*source_file as *const SourceFile)] - } - - /// Encode something with additional information that allows to do some - /// sanity checks when decoding the data again. This method will first - /// encode the specified tag, then the given value, then the number of - /// bytes taken up by tag and value. On decoding, we can then verify that - /// we get the expected tag and read the expected number of bytes. - fn encode_tagged<T: Encodable, V: Encodable>( - &mut self, - tag: T, - value: &V, - ) -> Result<(), E::Error> { - let start_pos = self.position(); - - tag.encode(self)?; - value.encode(self)?; - - let end_pos = self.position(); - ((end_pos - start_pos) as u64).encode(self) - } -} - -impl<'a, 'tcx, E> SpecializedEncoder<interpret::AllocId> for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { - use std::collections::hash_map::Entry; - let index = match self.interpret_allocs.entry(*alloc_id) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - let idx = self.interpret_allocs_inverse.len(); - self.interpret_allocs_inverse.push(*alloc_id); - e.insert(idx); - idx - } - }; - - index.encode(self) - } -} - -impl<'a, 'tcx, E> SpecializedEncoder<Span> for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> { - if *span == DUMMY_SP { - return TAG_INVALID_SPAN.encode(self); - } - - let span_data = span.data(); - let (file_lo, line_lo, col_lo) = - match self.source_map.byte_pos_to_line_and_col(span_data.lo) { - Some(pos) => pos, - None => return TAG_INVALID_SPAN.encode(self), - }; - - if !file_lo.contains(span_data.hi) { - return TAG_INVALID_SPAN.encode(self); - } - - let len = span_data.hi - span_data.lo; - - let source_file_index = self.source_file_index(file_lo); - - TAG_VALID_SPAN.encode(self)?; - source_file_index.encode(self)?; - line_lo.encode(self)?; - col_lo.encode(self)?; - len.encode(self)?; - - if span_data.ctxt == SyntaxContext::root() { - TAG_NO_EXPN_DATA.encode(self) - } else { - let (expn_id, transparency, expn_data) = span_data.ctxt.outer_mark_with_data(); - if let Some(pos) = self.expn_data_shorthands.get(&expn_id).cloned() { - TAG_EXPN_DATA_SHORTHAND.encode(self)?; - pos.encode(self) - } else { - TAG_EXPN_DATA_INLINE.encode(self)?; - let pos = AbsoluteBytePos::new(self.position()); - self.expn_data_shorthands.insert(expn_id, pos); - (expn_data, transparency).encode(self) - } - } - } -} - -impl<'a, 'tcx, E> SpecializedEncoder<Ident> for CacheEncoder<'a, 'tcx, E> -where - E: 'a + ty_codec::TyEncoder, -{ - fn specialized_encode(&mut self, _: &Ident) -> Result<(), Self::Error> { - // We don't currently encode enough information to ensure hygiene works - // with incremental, so panic rather than risk incremental bugs. - - // FIXME: handle hygiene in incremental. - bug!("trying to encode `Ident` for incremental"); - } -} - -impl<'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - #[inline] - fn position(&self) -> usize { - self.encoder.position() - } -} - -impl<'a, 'tcx, E> SpecializedEncoder<CrateNum> for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - #[inline] - fn specialized_encode(&mut self, cnum: &CrateNum) -> Result<(), Self::Error> { - self.emit_u32(cnum.as_u32()) - } -} - -impl<'a, 'tcx, E> SpecializedEncoder<Ty<'tcx>> for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - #[inline] - fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { - ty_codec::encode_with_shorthand(self, ty, |encoder| &mut encoder.type_shorthands) - } -} - -impl<'a, 'tcx, E> SpecializedEncoder<&'tcx [(ty::Predicate<'tcx>, Span)]> - for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - #[inline] - fn specialized_encode( - &mut self, - predicates: &&'tcx [(ty::Predicate<'tcx>, Span)], - ) -> Result<(), Self::Error> { - ty_codec::encode_spanned_predicates(self, predicates, |encoder| { - &mut encoder.predicate_shorthands - }) - } -} - -impl<'a, 'tcx, E> SpecializedEncoder<hir::HirId> for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - #[inline] - fn specialized_encode(&mut self, id: &hir::HirId) -> Result<(), Self::Error> { - let hir::HirId { owner, local_id } = *id; - - let def_path_hash = self.tcx.hir().definitions().def_path_hash(owner); - - def_path_hash.encode(self)?; - local_id.encode(self) - } -} - -impl<'a, 'tcx, E> SpecializedEncoder<DefId> for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - #[inline] - fn specialized_encode(&mut self, id: &DefId) -> Result<(), Self::Error> { - let def_path_hash = self.tcx.def_path_hash(*id); - def_path_hash.encode(self) - } -} - -impl<'a, 'tcx, E> SpecializedEncoder<LocalDefId> for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - #[inline] - fn specialized_encode(&mut self, id: &LocalDefId) -> Result<(), Self::Error> { - id.to_def_id().encode(self) - } -} - -impl<'a, 'tcx, E> SpecializedEncoder<DefIndex> for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - fn specialized_encode(&mut self, _: &DefIndex) -> Result<(), Self::Error> { - bug!("encoding `DefIndex` without context"); - } -} - -impl<'a, 'tcx> SpecializedEncoder<Fingerprint> for CacheEncoder<'a, 'tcx, opaque::Encoder> { - fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> { - f.encode_opaque(&mut self.encoder) - } -} - -impl<'a, 'tcx, E, T> SpecializedEncoder<mir::ClearCrossCrate<T>> for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, - T: Encodable, -{ - #[inline] - fn specialized_encode(&mut self, val: &mir::ClearCrossCrate<T>) -> Result<(), Self::Error> { - match *val { - mir::ClearCrossCrate::Clear => TAG_CLEAR_CROSS_CRATE_CLEAR.encode(self), - mir::ClearCrossCrate::Set(ref val) => { - TAG_CLEAR_CROSS_CRATE_SET.encode(self)?; - val.encode(self) - } - } - } -} - -macro_rules! encoder_methods { - ($($name:ident($ty:ty);)*) => { - #[inline] - $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> { - self.encoder.$name(value) - })* - } -} - -impl<'a, 'tcx, E> Encoder for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - type Error = E::Error; - - fn emit_unit(&mut self) -> Result<(), Self::Error> { - Ok(()) - } - - encoder_methods! { - emit_usize(usize); - emit_u128(u128); - emit_u64(u64); - emit_u32(u32); - emit_u16(u16); - emit_u8(u8); - - emit_isize(isize); - emit_i128(i128); - emit_i64(i64); - emit_i32(i32); - emit_i16(i16); - emit_i8(i8); - - emit_bool(bool); - emit_f64(f64); - emit_f32(f32); - emit_char(char); - emit_str(&str); - } -} - -// An integer that will always encode to 8 bytes. -struct IntEncodedWithFixedSize(u64); - -impl IntEncodedWithFixedSize { - pub const ENCODED_SIZE: usize = 8; -} - -impl UseSpecializedEncodable for IntEncodedWithFixedSize {} -impl UseSpecializedDecodable for IntEncodedWithFixedSize {} - -impl SpecializedEncoder<IntEncodedWithFixedSize> for opaque::Encoder { - fn specialized_encode(&mut self, x: &IntEncodedWithFixedSize) -> Result<(), Self::Error> { - let start_pos = self.position(); - for i in 0..IntEncodedWithFixedSize::ENCODED_SIZE { - ((x.0 >> (i * 8)) as u8).encode(self)?; - } - let end_pos = self.position(); - assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); - Ok(()) - } -} - -impl<'a> SpecializedDecoder<IntEncodedWithFixedSize> for opaque::Decoder<'a> { - fn specialized_decode(&mut self) -> Result<IntEncodedWithFixedSize, Self::Error> { - let mut value: u64 = 0; - let start_pos = self.position(); - - for i in 0..IntEncodedWithFixedSize::ENCODED_SIZE { - let byte: u8 = Decodable::decode(self)?; - value |= (byte as u64) << (i * 8); - } - - let end_pos = self.position(); - assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); - - Ok(IntEncodedWithFixedSize(value)) - } -} - -fn encode_query_results<'a, 'tcx, Q, E>( - tcx: TyCtxt<'tcx>, - encoder: &mut CacheEncoder<'a, 'tcx, E>, - query_result_index: &mut EncodedQueryResultIndex, -) -> Result<(), E::Error> -where - Q: super::config::QueryDescription<'tcx, Value: Encodable>, - E: 'a + TyEncoder, -{ - let _timer = tcx - .sess - .prof - .extra_verbose_generic_activity("encode_query_results_for", ::std::any::type_name::<Q>()); - - let state = Q::query_state(tcx); - assert!(state.all_inactive()); - - state.iter_results(|results| { - for (key, value, dep_node) in results { - if Q::cache_on_disk(tcx, key.clone(), Some(&value)) { - let dep_node = SerializedDepNodeIndex::new(dep_node.index()); - - // Record position of the cache entry. - query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position()))); - - // Encode the type check tables with the `SerializedDepNodeIndex` - // as tag. - encoder.encode_tagged(dep_node, &value)?; - } - } - Ok(()) - }) -} diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs deleted file mode 100644 index a61256b9fcb..00000000000 --- a/src/librustc/ty/query/plumbing.rs +++ /dev/null @@ -1,1266 +0,0 @@ -//! The implementation of the query system itself. This defines the macros that -//! generate the actual methods on tcx which find and execute the provider, -//! manage the caches, and so forth. - -use crate::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; -use crate::ty::query::caches::QueryCache; -use crate::ty::query::config::{QueryAccessors, QueryDescription}; -use crate::ty::query::job::{QueryInfo, QueryJob, QueryJobId, QueryShardJobId}; -use crate::ty::query::Query; -use crate::ty::tls; -use crate::ty::{self, TyCtxt}; - -#[cfg(not(parallel_compiler))] -use rustc_data_structures::cold_path; -use rustc_data_structures::fx::{FxHashMap, FxHasher}; -use rustc_data_structures::sharded::Sharded; -use rustc_data_structures::sync::{Lock, LockGuard}; -use rustc_data_structures::thin_vec::ThinVec; -use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, FatalError, Handler, Level}; -use rustc_span::source_map::DUMMY_SP; -use rustc_span::Span; -use std::collections::hash_map::Entry; -use std::hash::{Hash, Hasher}; -use std::mem; -use std::num::NonZeroU32; -use std::ptr; -#[cfg(debug_assertions)] -use std::sync::atomic::{AtomicUsize, Ordering}; - -pub(crate) struct QueryStateShard<'tcx, D: QueryAccessors<'tcx> + ?Sized> { - pub(super) cache: <<D as QueryAccessors<'tcx>>::Cache as QueryCache<D::Key, D::Value>>::Sharded, - pub(super) active: FxHashMap<D::Key, QueryResult<'tcx>>, - - /// Used to generate unique ids for active jobs. - pub(super) jobs: u32, -} - -impl<'tcx, Q: QueryAccessors<'tcx>> QueryStateShard<'tcx, Q> { - fn get_cache( - &mut self, - ) -> &mut <<Q as QueryAccessors<'tcx>>::Cache as QueryCache<Q::Key, Q::Value>>::Sharded { - &mut self.cache - } -} - -impl<'tcx, Q: QueryAccessors<'tcx>> Default for QueryStateShard<'tcx, Q> { - fn default() -> QueryStateShard<'tcx, Q> { - QueryStateShard { cache: Default::default(), active: Default::default(), jobs: 0 } - } -} - -pub(crate) struct QueryState<'tcx, D: QueryAccessors<'tcx> + ?Sized> { - pub(super) cache: D::Cache, - pub(super) shards: Sharded<QueryStateShard<'tcx, D>>, - #[cfg(debug_assertions)] - pub(super) cache_hits: AtomicUsize, -} - -impl<'tcx, Q: QueryAccessors<'tcx>> QueryState<'tcx, Q> { - pub(super) fn get_lookup<K: Hash>(&'tcx self, key: &K) -> QueryLookup<'tcx, Q> { - // We compute the key's hash once and then use it for both the - // shard lookup and the hashmap lookup. This relies on the fact - // that both of them use `FxHasher`. - let mut hasher = FxHasher::default(); - key.hash(&mut hasher); - let key_hash = hasher.finish(); - - let shard = self.shards.get_shard_index_by_hash(key_hash); - let lock = self.shards.get_shard_by_index(shard).lock(); - QueryLookup { key_hash, shard, lock } - } -} - -/// Indicates the state of a query for a given key in a query map. -pub(super) enum QueryResult<'tcx> { - /// An already executing query. The query job can be used to await for its completion. - Started(QueryJob<'tcx>), - - /// The query panicked. Queries trying to wait on this will raise a fatal error which will - /// silently panic. - Poisoned, -} - -impl<'tcx, M: QueryAccessors<'tcx>> QueryState<'tcx, M> { - pub fn iter_results<R>( - &self, - f: impl for<'a> FnOnce( - Box<dyn Iterator<Item = (&'a M::Key, &'a M::Value, DepNodeIndex)> + 'a>, - ) -> R, - ) -> R { - self.cache.iter(&self.shards, |shard| &mut shard.cache, f) - } - pub fn all_inactive(&self) -> bool { - let shards = self.shards.lock_shards(); - shards.iter().all(|shard| shard.active.is_empty()) - } -} - -impl<'tcx, M: QueryAccessors<'tcx>> Default for QueryState<'tcx, M> { - fn default() -> QueryState<'tcx, M> { - QueryState { - cache: M::Cache::default(), - shards: Default::default(), - #[cfg(debug_assertions)] - cache_hits: AtomicUsize::new(0), - } - } -} - -/// Values used when checking a query cache which can be reused on a cache-miss to execute the query. -pub(crate) struct QueryLookup<'tcx, Q: QueryAccessors<'tcx>> { - pub(super) key_hash: u64, - pub(super) shard: usize, - pub(super) lock: LockGuard<'tcx, QueryStateShard<'tcx, Q>>, -} - -/// A type representing the responsibility to execute the job in the `job` field. -/// This will poison the relevant query if dropped. -pub(super) struct JobOwner<'tcx, Q: QueryDescription<'tcx>> { - tcx: TyCtxt<'tcx>, - key: Q::Key, - id: QueryJobId, -} - -impl<'tcx, Q: QueryDescription<'tcx>> JobOwner<'tcx, Q> { - /// Either gets a `JobOwner` corresponding the query, allowing us to - /// start executing the query, or returns with the result of the query. - /// This function assumes that `try_get_cached` is already called and returned `lookup`. - /// If the query is executing elsewhere, this will wait for it and return the result. - /// If the query panicked, this will silently panic. - /// - /// This function is inlined because that results in a noticeable speed-up - /// for some compile-time benchmarks. - #[inline(always)] - pub(super) fn try_start( - tcx: TyCtxt<'tcx>, - span: Span, - key: &Q::Key, - mut lookup: QueryLookup<'tcx, Q>, - ) -> TryGetJob<'tcx, Q> { - let lock = &mut *lookup.lock; - - let (latch, mut _query_blocked_prof_timer) = match lock.active.entry((*key).clone()) { - Entry::Occupied(mut entry) => { - match entry.get_mut() { - QueryResult::Started(job) => { - // For parallel queries, we'll block and wait until the query running - // in another thread has completed. Record how long we wait in the - // self-profiler. - let _query_blocked_prof_timer = if cfg!(parallel_compiler) { - Some(tcx.prof.query_blocked()) - } else { - None - }; - - // Create the id of the job we're waiting for - let id = QueryJobId::new(job.id, lookup.shard, Q::dep_kind()); - - (job.latch(id), _query_blocked_prof_timer) - } - QueryResult::Poisoned => FatalError.raise(), - } - } - Entry::Vacant(entry) => { - // No job entry for this query. Return a new one to be started later. - - // Generate an id unique within this shard. - let id = lock.jobs.checked_add(1).unwrap(); - lock.jobs = id; - let id = QueryShardJobId(NonZeroU32::new(id).unwrap()); - - let global_id = QueryJobId::new(id, lookup.shard, Q::dep_kind()); - - let job = tls::with_related_context(tcx, |icx| QueryJob::new(id, span, icx.query)); - - entry.insert(QueryResult::Started(job)); - - let owner = JobOwner { tcx, id: global_id, key: (*key).clone() }; - return TryGetJob::NotYetStarted(owner); - } - }; - mem::drop(lookup.lock); - - // If we are single-threaded we know that we have cycle error, - // so we just return the error. - #[cfg(not(parallel_compiler))] - return TryGetJob::Cycle(cold_path(|| { - Q::handle_cycle_error(tcx, latch.find_cycle_in_stack(tcx, span)) - })); - - // With parallel queries we might just have to wait on some other - // thread. - #[cfg(parallel_compiler)] - { - let result = latch.wait_on(tcx, span); - - if let Err(cycle) = result { - return TryGetJob::Cycle(Q::handle_cycle_error(tcx, cycle)); - } - - let cached = tcx.try_get_cached::<Q, _, _, _>( - (*key).clone(), - |value, index| (value.clone(), index), - |_, _| panic!("value must be in cache after waiting"), - ); - - if let Some(prof_timer) = _query_blocked_prof_timer.take() { - prof_timer.finish_with_query_invocation_id(cached.1.into()); - } - - return TryGetJob::JobCompleted(cached); - } - } - - /// Completes the query by updating the query cache with the `result`, - /// signals the waiter and forgets the JobOwner, so it won't poison the query - #[inline(always)] - pub(super) fn complete(self, result: &Q::Value, dep_node_index: DepNodeIndex) { - // We can move out of `self` here because we `mem::forget` it below - let key = unsafe { ptr::read(&self.key) }; - let tcx = self.tcx; - - // Forget ourself so our destructor won't poison the query - mem::forget(self); - - let job = { - let state = Q::query_state(tcx); - let result = result.clone(); - let mut lock = state.shards.get_shard_by_value(&key).lock(); - let job = match lock.active.remove(&key).unwrap() { - QueryResult::Started(job) => job, - QueryResult::Poisoned => panic!(), - }; - state.cache.complete(tcx, &mut lock.cache, key, result, dep_node_index); - job - }; - - job.signal_complete(); - } -} - -#[inline(always)] -fn with_diagnostics<F, R>(f: F) -> (R, ThinVec<Diagnostic>) -where - F: FnOnce(Option<&Lock<ThinVec<Diagnostic>>>) -> R, -{ - let diagnostics = Lock::new(ThinVec::new()); - let result = f(Some(&diagnostics)); - (result, diagnostics.into_inner()) -} - -impl<'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'tcx, Q> { - #[inline(never)] - #[cold] - fn drop(&mut self) { - // Poison the query so jobs waiting on it panic. - let state = Q::query_state(self.tcx); - let shard = state.shards.get_shard_by_value(&self.key); - let job = { - let mut shard = shard.lock(); - let job = match shard.active.remove(&self.key).unwrap() { - QueryResult::Started(job) => job, - QueryResult::Poisoned => panic!(), - }; - shard.active.insert(self.key.clone(), QueryResult::Poisoned); - job - }; - // Also signal the completion of the job, so waiters - // will continue execution. - job.signal_complete(); - } -} - -#[derive(Clone)] -pub struct CycleError<'tcx> { - /// The query and related span that uses the cycle. - pub(super) usage: Option<(Span, Query<'tcx>)>, - pub(super) cycle: Vec<QueryInfo<'tcx>>, -} - -/// The result of `try_start`. -pub(super) enum TryGetJob<'tcx, D: QueryDescription<'tcx>> { - /// The query is not yet started. Contains a guard to the cache eventually used to start it. - NotYetStarted(JobOwner<'tcx, D>), - - /// The query was already completed. - /// Returns the result of the query and its dep-node index - /// if it succeeded or a cycle error if it failed. - #[cfg(parallel_compiler)] - JobCompleted((D::Value, DepNodeIndex)), - - /// Trying to execute the query resulted in a cycle. - Cycle(D::Value), -} - -impl<'tcx> TyCtxt<'tcx> { - /// Executes a job by changing the `ImplicitCtxt` to point to the - /// new query job while it executes. It returns the diagnostics - /// captured during execution and the actual result. - #[inline(always)] - pub(super) fn start_query<F, R>( - self, - token: QueryJobId, - diagnostics: Option<&Lock<ThinVec<Diagnostic>>>, - compute: F, - ) -> R - where - F: FnOnce(TyCtxt<'tcx>) -> R, - { - // The `TyCtxt` stored in TLS has the same global interner lifetime - // as `self`, so we use `with_related_context` to relate the 'tcx lifetimes - // when accessing the `ImplicitCtxt`. - tls::with_related_context(self, move |current_icx| { - // Update the `ImplicitCtxt` to point to our new query job. - let new_icx = tls::ImplicitCtxt { - tcx: self, - query: Some(token), - diagnostics, - layout_depth: current_icx.layout_depth, - task_deps: current_icx.task_deps, - }; - - // Use the `ImplicitCtxt` while we execute the query. - tls::enter_context(&new_icx, |_| compute(self)) - }) - } - - #[inline(never)] - #[cold] - pub(super) fn report_cycle( - self, - CycleError { usage, cycle: stack }: CycleError<'tcx>, - ) -> DiagnosticBuilder<'tcx> { - assert!(!stack.is_empty()); - - let fix_span = |span: Span, query: &Query<'tcx>| { - self.sess.source_map().def_span(query.default_span(self, span)) - }; - - // Disable naming impls with types in this path, since that - // sometimes cycles itself, leading to extra cycle errors. - // (And cycle errors around impls tend to occur during the - // collect/coherence phases anyhow.) - ty::print::with_forced_impl_filename_line(|| { - let span = fix_span(stack[1 % stack.len()].span, &stack[0].query); - let mut err = struct_span_err!( - self.sess, - span, - E0391, - "cycle detected when {}", - stack[0].query.describe(self) - ); - - for i in 1..stack.len() { - let query = &stack[i].query; - let span = fix_span(stack[(i + 1) % stack.len()].span, query); - err.span_note(span, &format!("...which requires {}...", query.describe(self))); - } - - err.note(&format!( - "...which again requires {}, completing the cycle", - stack[0].query.describe(self) - )); - - if let Some((span, query)) = usage { - err.span_note( - fix_span(span, &query), - &format!("cycle used when {}", query.describe(self)), - ); - } - - err - }) - } - - pub fn try_print_query_stack(handler: &Handler) { - eprintln!("query stack during panic:"); - - // Be careful reyling on global state here: this code is called from - // a panic hook, which means that the global `Handler` may be in a weird - // state if it was responsible for triggering the panic. - tls::with_context_opt(|icx| { - if let Some(icx) = icx { - let query_map = icx.tcx.queries.try_collect_active_jobs(); - - let mut current_query = icx.query; - let mut i = 0; - - while let Some(query) = current_query { - let query_info = - if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) { - info - } else { - break; - }; - let mut diag = Diagnostic::new( - Level::FailureNote, - &format!( - "#{} [{}] {}", - i, - query_info.info.query.name(), - query_info.info.query.describe(icx.tcx) - ), - ); - diag.span = icx.tcx.sess.source_map().def_span(query_info.info.span).into(); - handler.force_print_diagnostic(diag); - - current_query = query_info.job.parent; - i += 1; - } - } - }); - - eprintln!("end of query stack"); - } - - /// Checks if the query is already computed and in the cache. - /// It returns the shard index and a lock guard to the shard, - /// which will be used if the query is not in the cache and we need - /// to compute it. - #[inline(always)] - fn try_get_cached<Q, R, OnHit, OnMiss>( - self, - key: Q::Key, - // `on_hit` can be called while holding a lock to the query cache - on_hit: OnHit, - on_miss: OnMiss, - ) -> R - where - Q: QueryDescription<'tcx> + 'tcx, - OnHit: FnOnce(&Q::Value, DepNodeIndex) -> R, - OnMiss: FnOnce(Q::Key, QueryLookup<'tcx, Q>) -> R, - { - let state = Q::query_state(self); - - state.cache.lookup( - state, - QueryStateShard::<Q>::get_cache, - key, - |value, index| { - if unlikely!(self.prof.enabled()) { - self.prof.query_cache_hit(index.into()); - } - #[cfg(debug_assertions)] - { - state.cache_hits.fetch_add(1, Ordering::Relaxed); - } - on_hit(value, index) - }, - on_miss, - ) - } - - #[inline(never)] - pub(super) fn get_query<Q: QueryDescription<'tcx> + 'tcx>( - self, - span: Span, - key: Q::Key, - ) -> Q::Value { - debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span); - - self.try_get_cached::<Q, _, _, _>( - key, - |value, index| { - self.dep_graph.read_index(index); - value.clone() - }, - |key, lookup| self.try_execute_query::<Q>(span, key, lookup), - ) - } - - #[inline(always)] - pub(super) fn try_execute_query<Q: QueryDescription<'tcx>>( - self, - span: Span, - key: Q::Key, - lookup: QueryLookup<'tcx, Q>, - ) -> Q::Value { - let job = match JobOwner::try_start(self, span, &key, lookup) { - TryGetJob::NotYetStarted(job) => job, - TryGetJob::Cycle(result) => return result, - #[cfg(parallel_compiler)] - TryGetJob::JobCompleted((v, index)) => { - self.dep_graph.read_index(index); - return v; - } - }; - - // Fast path for when incr. comp. is off. `to_dep_node` is - // expensive for some `DepKind`s. - if !self.dep_graph.is_fully_enabled() { - let null_dep_node = DepNode::new_no_params(crate::dep_graph::DepKind::Null); - return self.force_query_with_job::<Q>(key, job, null_dep_node).0; - } - - if Q::ANON { - let prof_timer = self.prof.query_provider(); - - let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { - self.start_query(job.id, diagnostics, |tcx| { - tcx.dep_graph.with_anon_task(Q::dep_kind(), || Q::compute(tcx, key)) - }) - }); - - prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - - self.dep_graph.read_index(dep_node_index); - - if unlikely!(!diagnostics.is_empty()) { - self.queries - .on_disk_cache - .store_diagnostics_for_anon_node(dep_node_index, diagnostics); - } - - job.complete(&result, dep_node_index); - - return result; - } - - let dep_node = Q::to_dep_node(self, &key); - - if !Q::EVAL_ALWAYS { - // The diagnostics for this query will be - // promoted to the current session during - // `try_mark_green()`, so we can ignore them here. - let loaded = self.start_query(job.id, None, |tcx| { - let marked = tcx.dep_graph.try_mark_green_and_read(tcx, &dep_node); - marked.map(|(prev_dep_node_index, dep_node_index)| { - ( - tcx.load_from_disk_and_cache_in_memory::<Q>( - key.clone(), - prev_dep_node_index, - dep_node_index, - &dep_node, - ), - dep_node_index, - ) - }) - }); - if let Some((result, dep_node_index)) = loaded { - job.complete(&result, dep_node_index); - return result; - } - } - - let (result, dep_node_index) = self.force_query_with_job::<Q>(key, job, dep_node); - self.dep_graph.read_index(dep_node_index); - result - } - - fn load_from_disk_and_cache_in_memory<Q: QueryDescription<'tcx>>( - self, - key: Q::Key, - prev_dep_node_index: SerializedDepNodeIndex, - dep_node_index: DepNodeIndex, - dep_node: &DepNode, - ) -> Q::Value { - // Note this function can be called concurrently from the same query - // We must ensure that this is handled correctly. - - debug_assert!(self.dep_graph.is_green(dep_node)); - - // First we try to load the result from the on-disk cache. - let result = if Q::cache_on_disk(self, key.clone(), None) - && self.sess.opts.debugging_opts.incremental_queries - { - let prof_timer = self.prof.incr_cache_loading(); - let result = Q::try_load_from_disk(self, prev_dep_node_index); - prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - - // We always expect to find a cached result for things that - // can be forced from `DepNode`. - debug_assert!( - !dep_node.kind.can_reconstruct_query_key() || result.is_some(), - "missing on-disk cache entry for {:?}", - dep_node - ); - result - } else { - // Some things are never cached on disk. - None - }; - - let result = if let Some(result) = result { - result - } else { - // We could not load a result from the on-disk cache, so - // recompute. - let prof_timer = self.prof.query_provider(); - - // The dep-graph for this computation is already in-place. - let result = self.dep_graph.with_ignore(|| Q::compute(self, key)); - - prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - - result - }; - - // If `-Zincremental-verify-ich` is specified, re-hash results from - // the cache and make sure that they have the expected fingerprint. - if unlikely!(self.sess.opts.debugging_opts.incremental_verify_ich) { - self.incremental_verify_ich::<Q>(&result, dep_node, dep_node_index); - } - - result - } - - #[inline(never)] - #[cold] - fn incremental_verify_ich<Q: QueryDescription<'tcx>>( - self, - result: &Q::Value, - dep_node: &DepNode, - dep_node_index: DepNodeIndex, - ) { - use crate::ich::Fingerprint; - - assert!( - Some(self.dep_graph.fingerprint_of(dep_node_index)) - == self.dep_graph.prev_fingerprint_of(dep_node), - "fingerprint for green query instance not loaded from cache: {:?}", - dep_node, - ); - - debug!("BEGIN verify_ich({:?})", dep_node); - let mut hcx = self.create_stable_hashing_context(); - - let new_hash = Q::hash_result(&mut hcx, result).unwrap_or(Fingerprint::ZERO); - debug!("END verify_ich({:?})", dep_node); - - let old_hash = self.dep_graph.fingerprint_of(dep_node_index); - - assert!(new_hash == old_hash, "found unstable fingerprints for {:?}", dep_node,); - } - - #[inline(always)] - fn force_query_with_job<Q: QueryDescription<'tcx>>( - self, - key: Q::Key, - job: JobOwner<'tcx, Q>, - dep_node: DepNode, - ) -> (Q::Value, DepNodeIndex) { - // If the following assertion triggers, it can have two reasons: - // 1. Something is wrong with DepNode creation, either here or - // in `DepGraph::try_mark_green()`. - // 2. Two distinct query keys get mapped to the same `DepNode` - // (see for example #48923). - assert!( - !self.dep_graph.dep_node_exists(&dep_node), - "forcing query with already existing `DepNode`\n\ - - query-key: {:?}\n\ - - dep-node: {:?}", - key, - dep_node - ); - - let prof_timer = self.prof.query_provider(); - - let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { - self.start_query(job.id, diagnostics, |tcx| { - if Q::EVAL_ALWAYS { - tcx.dep_graph.with_eval_always_task( - dep_node, - tcx, - key, - Q::compute, - Q::hash_result, - ) - } else { - tcx.dep_graph.with_task(dep_node, tcx, key, Q::compute, Q::hash_result) - } - }) - }); - - prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - - if unlikely!(!diagnostics.is_empty()) { - if dep_node.kind != crate::dep_graph::DepKind::Null { - self.queries.on_disk_cache.store_diagnostics(dep_node_index, diagnostics); - } - } - - job.complete(&result, dep_node_index); - - (result, dep_node_index) - } - - /// Ensure that either this query has all green inputs or been executed. - /// Executing `query::ensure(D)` is considered a read of the dep-node `D`. - /// - /// This function is particularly useful when executing passes for their - /// side-effects -- e.g., in order to report errors for erroneous programs. - /// - /// Note: The optimization is only available during incr. comp. - pub(super) fn ensure_query<Q: QueryDescription<'tcx> + 'tcx>(self, key: Q::Key) -> () { - if Q::EVAL_ALWAYS { - let _ = self.get_query::<Q>(DUMMY_SP, key); - return; - } - - // Ensuring an anonymous query makes no sense - assert!(!Q::ANON); - - let dep_node = Q::to_dep_node(self, &key); - - match self.dep_graph.try_mark_green_and_read(self, &dep_node) { - None => { - // A None return from `try_mark_green_and_read` means that this is either - // a new dep node or that the dep node has already been marked red. - // Either way, we can't call `dep_graph.read()` as we don't have the - // DepNodeIndex. We must invoke the query itself. The performance cost - // this introduces should be negligible as we'll immediately hit the - // in-memory cache, or another query down the line will. - let _ = self.get_query::<Q>(DUMMY_SP, key); - } - Some((_, dep_node_index)) => { - self.prof.query_cache_hit(dep_node_index.into()); - } - } - } - - #[allow(dead_code)] - fn force_query<Q: QueryDescription<'tcx> + 'tcx>( - self, - key: Q::Key, - span: Span, - dep_node: DepNode, - ) { - // We may be concurrently trying both execute and force a query. - // Ensure that only one of them runs the query. - - self.try_get_cached::<Q, _, _, _>( - key, - |_, _| { - // Cache hit, do nothing - }, - |key, lookup| { - let job = match JobOwner::try_start(self, span, &key, lookup) { - TryGetJob::NotYetStarted(job) => job, - TryGetJob::Cycle(_) => return, - #[cfg(parallel_compiler)] - TryGetJob::JobCompleted(_) => return, - }; - self.force_query_with_job::<Q>(key, job, dep_node); - }, - ); - } -} - -macro_rules! handle_cycle_error { - ([][$tcx: expr, $error:expr]) => {{ - $tcx.report_cycle($error).emit(); - Value::from_cycle_error($tcx) - }}; - ([fatal_cycle $($rest:tt)*][$tcx:expr, $error:expr]) => {{ - $tcx.report_cycle($error).emit(); - $tcx.sess.abort_if_errors(); - unreachable!() - }}; - ([cycle_delay_bug $($rest:tt)*][$tcx:expr, $error:expr]) => {{ - $tcx.report_cycle($error).delay_as_bug(); - Value::from_cycle_error($tcx) - }}; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => { - handle_cycle_error!([$($($modifiers)*)*][$($args)*]) - }; -} - -macro_rules! is_anon { - ([]) => {{ - false - }}; - ([anon $($rest:tt)*]) => {{ - true - }}; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => { - is_anon!([$($($modifiers)*)*]) - }; -} - -macro_rules! is_eval_always { - ([]) => {{ - false - }}; - ([eval_always $($rest:tt)*]) => {{ - true - }}; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => { - is_eval_always!([$($($modifiers)*)*]) - }; -} - -macro_rules! query_storage { - ([][$K:ty, $V:ty]) => { - <<$K as Key>::CacheSelector as CacheSelector<$K, $V>>::Cache - }; - ([storage($ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => { - $ty - }; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => { - query_storage!([$($($modifiers)*)*][$($args)*]) - }; -} - -macro_rules! hash_result { - ([][$hcx:expr, $result:expr]) => {{ - dep_graph::hash_result($hcx, &$result) - }}; - ([no_hash $($rest:tt)*][$hcx:expr, $result:expr]) => {{ - None - }}; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => { - hash_result!([$($($modifiers)*)*][$($args)*]) - }; -} - -macro_rules! define_queries { - (<$tcx:tt> $($category:tt { - $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)* - },)*) => { - define_queries_inner! { <$tcx> - $($( $(#[$attr])* category<$category> [$($modifiers)*] fn $name: $node($K) -> $V,)*)* - } - } -} - -macro_rules! define_queries_inner { - (<$tcx:tt> - $($(#[$attr:meta])* category<$category:tt> - [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { - - use std::mem; - use crate::{ - rustc_data_structures::stable_hasher::HashStable, - rustc_data_structures::stable_hasher::StableHasher, - ich::StableHashingContext - }; - use rustc_data_structures::profiling::ProfileCategory; - - define_queries_struct! { - tcx: $tcx, - input: ($(([$($modifiers)*] [$($attr)*] [$name]))*) - } - - impl<$tcx> Queries<$tcx> { - pub fn new( - providers: IndexVec<CrateNum, Providers<$tcx>>, - fallback_extern_providers: Providers<$tcx>, - on_disk_cache: OnDiskCache<'tcx>, - ) -> Self { - Queries { - providers, - fallback_extern_providers: Box::new(fallback_extern_providers), - on_disk_cache, - $($name: Default::default()),* - } - } - - pub fn try_collect_active_jobs( - &self - ) -> Option<FxHashMap<QueryJobId, QueryJobInfo<'tcx>>> { - let mut jobs = FxHashMap::default(); - - $( - // We use try_lock_shards here since we are called from the - // deadlock handler, and this shouldn't be locked. - let shards = self.$name.shards.try_lock_shards()?; - let shards = shards.iter().enumerate(); - jobs.extend(shards.flat_map(|(shard_id, shard)| { - shard.active.iter().filter_map(move |(k, v)| { - if let QueryResult::Started(ref job) = *v { - let id = QueryJobId { - job: job.id, - shard: u16::try_from(shard_id).unwrap(), - kind: - <queries::$name<'tcx> as QueryAccessors<'tcx>>::dep_kind(), - }; - let info = QueryInfo { - span: job.span, - query: queries::$name::query(k.clone()) - }; - Some((id, QueryJobInfo { info, job: job.clone() })) - } else { - None - } - }) - })); - )* - - Some(jobs) - } - } - - #[allow(nonstandard_style)] - #[derive(Clone, Debug)] - pub enum Query<$tcx> { - $($(#[$attr])* $name($K)),* - } - - impl<$tcx> Query<$tcx> { - pub fn name(&self) -> &'static str { - match *self { - $(Query::$name(_) => stringify!($name),)* - } - } - - pub fn describe(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> { - let (r, name) = match *self { - $(Query::$name(key) => { - (queries::$name::describe(tcx, key), stringify!($name)) - })* - }; - if tcx.sess.verbose() { - format!("{} [{}]", r, name).into() - } else { - r - } - } - - // FIXME(eddyb) Get more valid `Span`s on queries. - pub fn default_span(&self, tcx: TyCtxt<$tcx>, span: Span) -> Span { - if !span.is_dummy() { - return span; - } - // The `def_span` query is used to calculate `default_span`, - // so exit to avoid infinite recursion. - if let Query::def_span(..) = *self { - return span - } - match *self { - $(Query::$name(key) => key.default_span(tcx),)* - } - } - } - - impl<'a, $tcx> HashStable<StableHashingContext<'a>> for Query<$tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - $(Query::$name(key) => key.hash_stable(hcx, hasher),)* - } - } - } - - pub mod queries { - use std::marker::PhantomData; - - $(#[allow(nonstandard_style)] - pub struct $name<$tcx> { - data: PhantomData<&$tcx ()> - })* - } - - // This module and the functions in it exist only to provide a - // predictable symbol name prefix for query providers. This is helpful - // for analyzing queries in profilers. - pub(super) mod __query_compute { - $(#[inline(never)] - pub fn $name<F: FnOnce() -> R, R>(f: F) -> R { - f() - })* - } - - $(impl<$tcx> QueryConfig<$tcx> for queries::$name<$tcx> { - type Key = $K; - type Value = $V; - const NAME: &'static str = stringify!($name); - const CATEGORY: ProfileCategory = $category; - } - - impl<$tcx> QueryAccessors<$tcx> for queries::$name<$tcx> { - const ANON: bool = is_anon!([$($modifiers)*]); - const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]); - - type Cache = query_storage!([$($modifiers)*][$K, $V]); - - #[inline(always)] - fn query(key: Self::Key) -> Query<'tcx> { - Query::$name(key) - } - - #[inline(always)] - fn query_state<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryState<$tcx, Self> { - &tcx.queries.$name - } - - #[allow(unused)] - #[inline(always)] - fn to_dep_node(tcx: TyCtxt<$tcx>, key: &Self::Key) -> DepNode { - DepConstructor::$node(tcx, *key) - } - - #[inline(always)] - fn dep_kind() -> dep_graph::DepKind { - dep_graph::DepKind::$node - } - - #[inline] - fn compute(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value { - __query_compute::$name(move || { - let provider = tcx.queries.providers.get(key.query_crate()) - // HACK(eddyb) it's possible crates may be loaded after - // the query engine is created, and because crate loading - // is not yet integrated with the query engine, such crates - // would be missing appropriate entries in `providers`. - .unwrap_or(&tcx.queries.fallback_extern_providers) - .$name; - provider(tcx, key) - }) - } - - fn hash_result( - _hcx: &mut StableHashingContext<'_>, - _result: &Self::Value - ) -> Option<Fingerprint> { - hash_result!([$($modifiers)*][_hcx, _result]) - } - - fn handle_cycle_error( - tcx: TyCtxt<'tcx>, - error: CycleError<'tcx> - ) -> Self::Value { - handle_cycle_error!([$($modifiers)*][tcx, error]) - } - })* - - #[derive(Copy, Clone)] - pub struct TyCtxtEnsure<'tcx> { - pub tcx: TyCtxt<'tcx>, - } - - impl TyCtxtEnsure<$tcx> { - $($(#[$attr])* - #[inline(always)] - pub fn $name(self, key: $K) { - self.tcx.ensure_query::<queries::$name<'_>>(key) - })* - } - - #[derive(Copy, Clone)] - pub struct TyCtxtAt<'tcx> { - pub tcx: TyCtxt<'tcx>, - pub span: Span, - } - - impl Deref for TyCtxtAt<'tcx> { - type Target = TyCtxt<'tcx>; - #[inline(always)] - fn deref(&self) -> &Self::Target { - &self.tcx - } - } - - impl TyCtxt<$tcx> { - /// Returns a transparent wrapper for `TyCtxt`, which ensures queries - /// are executed instead of just returing their results. - #[inline(always)] - pub fn ensure(self) -> TyCtxtEnsure<$tcx> { - TyCtxtEnsure { - tcx: self, - } - } - - /// Returns a transparent wrapper for `TyCtxt` which uses - /// `span` as the location of queries performed through it. - #[inline(always)] - pub fn at(self, span: Span) -> TyCtxtAt<$tcx> { - TyCtxtAt { - tcx: self, - span - } - } - - $($(#[$attr])* - #[inline(always)] - pub fn $name(self, key: $K) -> $V { - self.at(DUMMY_SP).$name(key) - })* - - /// All self-profiling events generated by the query engine use - /// virtual `StringId`s for their `event_id`. This method makes all - /// those virtual `StringId`s point to actual strings. - /// - /// If we are recording only summary data, the ids will point to - /// just the query names. If we are recording query keys too, we - /// allocate the corresponding strings here. - pub fn alloc_self_profile_query_strings(self) { - use crate::ty::query::profiling_support::{ - alloc_self_profile_query_strings_for_query_cache, - QueryKeyStringCache, - }; - - if !self.prof.enabled() { - return; - } - - let mut string_cache = QueryKeyStringCache::new(); - - $({ - alloc_self_profile_query_strings_for_query_cache( - self, - stringify!($name), - &self.queries.$name, - &mut string_cache, - ); - })* - } - } - - impl TyCtxtAt<$tcx> { - $($(#[$attr])* - #[inline(always)] - pub fn $name(self, key: $K) -> $V { - self.tcx.get_query::<queries::$name<'_>>(self.span, key) - })* - } - - define_provider_struct! { - tcx: $tcx, - input: ($(([$($modifiers)*] [$name] [$K] [$V]))*) - } - - impl<$tcx> Copy for Providers<$tcx> {} - impl<$tcx> Clone for Providers<$tcx> { - fn clone(&self) -> Self { *self } - } - } -} - -macro_rules! define_queries_struct { - (tcx: $tcx:tt, - input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { - pub struct Queries<$tcx> { - /// This provides access to the incrimental comilation on-disk cache for query results. - /// Do not access this directly. It is only meant to be used by - /// `DepGraph::try_mark_green()` and the query infrastructure. - pub(crate) on_disk_cache: OnDiskCache<'tcx>, - - providers: IndexVec<CrateNum, Providers<$tcx>>, - fallback_extern_providers: Box<Providers<$tcx>>, - - $($(#[$attr])* $name: QueryState<$tcx, queries::$name<$tcx>>,)* - } - }; -} - -macro_rules! define_provider_struct { - (tcx: $tcx:tt, - input: ($(([$($modifiers:tt)*] [$name:ident] [$K:ty] [$R:ty]))*)) => { - pub struct Providers<$tcx> { - $(pub $name: fn(TyCtxt<$tcx>, $K) -> $R,)* - } - - impl<$tcx> Default for Providers<$tcx> { - fn default() -> Self { - $(fn $name<$tcx>(_: TyCtxt<$tcx>, key: $K) -> $R { - bug!("`tcx.{}({:?})` unsupported by its crate", - stringify!($name), key); - })* - Providers { $($name),* } - } - } - }; -} - -/// The red/green evaluation system will try to mark a specific DepNode in the -/// dependency graph as green by recursively trying to mark the dependencies of -/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` -/// where we don't know if it is red or green and we therefore actually have -/// to recompute its value in order to find out. Since the only piece of -/// information that we have at that point is the `DepNode` we are trying to -/// re-evaluate, we need some way to re-run a query from just that. This is what -/// `force_from_dep_node()` implements. -/// -/// In the general case, a `DepNode` consists of a `DepKind` and an opaque -/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint -/// is usually constructed by computing a stable hash of the query-key that the -/// `DepNode` corresponds to. Consequently, it is not in general possible to go -/// back from hash to query-key (since hash functions are not reversible). For -/// this reason `force_from_dep_node()` is expected to fail from time to time -/// because we just cannot find out, from the `DepNode` alone, what the -/// corresponding query-key is and therefore cannot re-run the query. -/// -/// The system deals with this case letting `try_mark_green` fail which forces -/// the root query to be re-evaluated. -/// -/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. -/// Fortunately, we can use some contextual information that will allow us to -/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we -/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a -/// valid `DefPathHash`. Since we also always build a huge table that maps every -/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have -/// everything we need to re-run the query. -/// -/// Take the `mir_validated` query as an example. Like many other queries, it -/// just has a single parameter: the `DefId` of the item it will compute the -/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` -/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` -/// is actually a `DefPathHash`, and can therefore just look up the corresponding -/// `DefId` in `tcx.def_path_hash_to_def_id`. -/// -/// When you implement a new query, it will likely have a corresponding new -/// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As -/// a rule of thumb, if your query takes a `DefId` or `DefIndex` as sole parameter, -/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just -/// add it to the "We don't have enough information to reconstruct..." group in -/// the match below. -pub fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool { - use crate::dep_graph::RecoverKey; - - // We must avoid ever having to call `force_from_dep_node()` for a - // `DepNode::codegen_unit`: - // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we - // would always end up having to evaluate the first caller of the - // `codegen_unit` query that *is* reconstructible. This might very well be - // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just - // to re-trigger calling the `codegen_unit` query with the right key. At - // that point we would already have re-done all the work we are trying to - // avoid doing in the first place. - // The solution is simple: Just explicitly call the `codegen_unit` query for - // each CGU, right after partitioning. This way `try_mark_green` will always - // hit the cache instead of having to go through `force_from_dep_node`. - // This assertion makes sure, we actually keep applying the solution above. - debug_assert!( - dep_node.kind != DepKind::codegen_unit, - "calling force_from_dep_node() on DepKind::codegen_unit" - ); - - if !dep_node.kind.can_reconstruct_query_key() { - return false; - } - - rustc_dep_node_force!([dep_node, tcx] - // These are inputs that are expected to be pre-allocated and that - // should therefore always be red or green already. - DepKind::AllLocalTraitImpls | - DepKind::CrateMetadata | - DepKind::HirBody | - DepKind::Hir | - - // These are anonymous nodes. - DepKind::TraitSelect | - - // We don't have enough information to reconstruct the query key of - // these. - DepKind::CompileCodegenUnit => { - bug!("force_from_dep_node: encountered {:?}", dep_node) - } - - DepKind::Analysis => { - let def_id = if let Some(def_id) = dep_node.extract_def_id(tcx) { - def_id - } else { - // Return from the whole function. - return false - }; - tcx.force_query::<crate::ty::query::queries::analysis<'_>>( - def_id.krate, - DUMMY_SP, - *dep_node - ); - } - ); - - true -} diff --git a/src/librustc/ty/query/profiling_support.rs b/src/librustc/ty/query/profiling_support.rs deleted file mode 100644 index 99ada34d59e..00000000000 --- a/src/librustc/ty/query/profiling_support.rs +++ /dev/null @@ -1,218 +0,0 @@ -use crate::hir::map::definitions::DefPathData; -use crate::ty::context::TyCtxt; -use crate::ty::query::config::QueryAccessors; -use crate::ty::query::plumbing::QueryState; -use measureme::{StringComponent, StringId}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::profiling::SelfProfiler; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; -use std::fmt::Debug; -use std::io::Write; - -pub struct QueryKeyStringCache { - def_id_cache: FxHashMap<DefId, StringId>, -} - -impl QueryKeyStringCache { - pub fn new() -> QueryKeyStringCache { - QueryKeyStringCache { def_id_cache: Default::default() } - } -} - -pub struct QueryKeyStringBuilder<'p, 'c, 'tcx> { - profiler: &'p SelfProfiler, - tcx: TyCtxt<'tcx>, - string_cache: &'c mut QueryKeyStringCache, -} - -impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { - pub fn new( - profiler: &'p SelfProfiler, - tcx: TyCtxt<'tcx>, - string_cache: &'c mut QueryKeyStringCache, - ) -> QueryKeyStringBuilder<'p, 'c, 'tcx> { - QueryKeyStringBuilder { profiler, tcx, string_cache } - } - - // The current implementation is rather crude. In the future it might be a - // good idea to base this on `ty::print` in order to get nicer and more - // efficient query keys. - fn def_id_to_string_id(&mut self, def_id: DefId) -> StringId { - if let Some(&string_id) = self.string_cache.def_id_cache.get(&def_id) { - return string_id; - } - - let def_key = self.tcx.def_key(def_id); - - let (parent_string_id, start_index) = match def_key.parent { - Some(parent_index) => { - let parent_def_id = DefId { index: parent_index, krate: def_id.krate }; - - (self.def_id_to_string_id(parent_def_id), 0) - } - None => (StringId::INVALID, 2), - }; - - let dis_buffer = &mut [0u8; 16]; - let name; - let dis; - let end_index; - - match def_key.disambiguated_data.data { - DefPathData::CrateRoot => { - name = self.tcx.original_crate_name(def_id.krate).as_str(); - dis = ""; - end_index = 3; - } - other => { - name = other.as_symbol().as_str(); - if def_key.disambiguated_data.disambiguator == 0 { - dis = ""; - end_index = 3; - } else { - write!(&mut dis_buffer[..], "[{}]", def_key.disambiguated_data.disambiguator) - .unwrap(); - let end_of_dis = dis_buffer.iter().position(|&c| c == b']').unwrap(); - dis = std::str::from_utf8(&dis_buffer[..end_of_dis + 1]).unwrap(); - end_index = 4; - } - } - } - - let components = [ - StringComponent::Ref(parent_string_id), - StringComponent::Value("::"), - StringComponent::Value(&name[..]), - StringComponent::Value(dis), - ]; - - let string_id = self.profiler.alloc_string(&components[start_index..end_index]); - - self.string_cache.def_id_cache.insert(def_id, string_id); - - string_id - } -} - -pub trait IntoSelfProfilingString { - fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId; -} - -// The default implementation of `IntoSelfProfilingString` just uses `Debug` -// which is slow and causes lots of duplication of string data. -// The specialized impls below take care of making the `DefId` case more -// efficient. -impl<T: Debug> IntoSelfProfilingString for T { - default fn to_self_profile_string( - &self, - builder: &mut QueryKeyStringBuilder<'_, '_, '_>, - ) -> StringId { - let s = format!("{:?}", self); - builder.profiler.alloc_string(&s[..]) - } -} - -impl IntoSelfProfilingString for DefId { - fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId { - builder.def_id_to_string_id(*self) - } -} - -impl IntoSelfProfilingString for CrateNum { - fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId { - builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX }) - } -} - -impl IntoSelfProfilingString for DefIndex { - fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId { - builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self }) - } -} - -impl<T0, T1> IntoSelfProfilingString for (T0, T1) -where - T0: IntoSelfProfilingString + Debug, - T1: IntoSelfProfilingString + Debug, -{ - default fn to_self_profile_string( - &self, - builder: &mut QueryKeyStringBuilder<'_, '_, '_>, - ) -> StringId { - let val0 = self.0.to_self_profile_string(builder); - let val1 = self.1.to_self_profile_string(builder); - - let components = &[ - StringComponent::Value("("), - StringComponent::Ref(val0), - StringComponent::Value(","), - StringComponent::Ref(val1), - StringComponent::Value(")"), - ]; - - builder.profiler.alloc_string(components) - } -} - -/// Allocate the self-profiling query strings for a single query cache. This -/// method is called from `alloc_self_profile_query_strings` which knows all -/// the queries via macro magic. -pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, Q>( - tcx: TyCtxt<'tcx>, - query_name: &'static str, - query_state: &QueryState<'tcx, Q>, - string_cache: &mut QueryKeyStringCache, -) where - Q: QueryAccessors<'tcx>, -{ - tcx.prof.with_profiler(|profiler| { - let event_id_builder = profiler.event_id_builder(); - - // Walk the entire query cache and allocate the appropriate - // string representations. Each cache entry is uniquely - // identified by its dep_node_index. - if profiler.query_key_recording_enabled() { - let mut query_string_builder = QueryKeyStringBuilder::new(profiler, tcx, string_cache); - - let query_name = profiler.get_or_alloc_cached_string(query_name); - - // Since building the string representation of query keys might - // need to invoke queries itself, we cannot keep the query caches - // locked while doing so. Instead we copy out the - // `(query_key, dep_node_index)` pairs and release the lock again. - let query_keys_and_indices: Vec<_> = query_state - .iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect()); - - // Now actually allocate the strings. If allocating the strings - // generates new entries in the query cache, we'll miss them but - // we don't actually care. - for (query_key, dep_node_index) in query_keys_and_indices { - // Translate the DepNodeIndex into a QueryInvocationId - let query_invocation_id = dep_node_index.into(); - - // Create the string version of the query-key - let query_key = query_key.to_self_profile_string(&mut query_string_builder); - let event_id = event_id_builder.from_label_and_arg(query_name, query_key); - - // Doing this in bulk might be a good idea: - profiler.map_query_invocation_id_to_string( - query_invocation_id, - event_id.to_string_id(), - ); - } - } else { - // In this branch we don't allocate query keys - let query_name = profiler.get_or_alloc_cached_string(query_name); - let event_id = event_id_builder.from_label(query_name).to_string_id(); - - query_state.iter_results(|results| { - let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect(); - - profiler.bulk_map_query_invocation_id_to_single_string( - query_invocation_ids.into_iter(), - event_id, - ); - }); - } - }); -} diff --git a/src/librustc/ty/query/stats.rs b/src/librustc/ty/query/stats.rs deleted file mode 100644 index d257320d4ea..00000000000 --- a/src/librustc/ty/query/stats.rs +++ /dev/null @@ -1,139 +0,0 @@ -use crate::ty::query::config::QueryAccessors; -use crate::ty::query::plumbing::QueryState; -use crate::ty::query::queries; -use crate::ty::TyCtxt; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; - -use std::any::type_name; -use std::mem; -#[cfg(debug_assertions)] -use std::sync::atomic::Ordering; - -trait KeyStats { - fn key_stats(&self, stats: &mut QueryStats); -} - -impl<T> KeyStats for T { - default fn key_stats(&self, _: &mut QueryStats) {} -} - -impl KeyStats for DefId { - fn key_stats(&self, stats: &mut QueryStats) { - if self.krate == LOCAL_CRATE { - stats.local_def_id_keys = Some(stats.local_def_id_keys.unwrap_or(0) + 1); - } - } -} - -#[derive(Clone)] -struct QueryStats { - name: &'static str, - cache_hits: usize, - key_size: usize, - key_type: &'static str, - value_size: usize, - value_type: &'static str, - entry_count: usize, - local_def_id_keys: Option<usize>, -} - -fn stats<'tcx, Q: QueryAccessors<'tcx>>( - name: &'static str, - map: &QueryState<'tcx, Q>, -) -> QueryStats { - let mut stats = QueryStats { - name, - #[cfg(debug_assertions)] - cache_hits: map.cache_hits.load(Ordering::Relaxed), - #[cfg(not(debug_assertions))] - cache_hits: 0, - key_size: mem::size_of::<Q::Key>(), - key_type: type_name::<Q::Key>(), - value_size: mem::size_of::<Q::Value>(), - value_type: type_name::<Q::Value>(), - entry_count: map.iter_results(|results| results.count()), - local_def_id_keys: None, - }; - map.iter_results(|results| { - for (key, _, _) in results { - key.key_stats(&mut stats) - } - }); - stats -} - -pub fn print_stats(tcx: TyCtxt<'_>) { - let queries = query_stats(tcx); - - if cfg!(debug_assertions) { - let hits: usize = queries.iter().map(|s| s.cache_hits).sum(); - let results: usize = queries.iter().map(|s| s.entry_count).sum(); - println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64); - } - - let mut query_key_sizes = queries.clone(); - query_key_sizes.sort_by_key(|q| q.key_size); - println!("\nLarge query keys:"); - for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) { - println!(" {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type); - } - - let mut query_value_sizes = queries.clone(); - query_value_sizes.sort_by_key(|q| q.value_size); - println!("\nLarge query values:"); - for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) { - println!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type); - } - - if cfg!(debug_assertions) { - let mut query_cache_hits = queries.clone(); - query_cache_hits.sort_by_key(|q| q.cache_hits); - println!("\nQuery cache hits:"); - for q in query_cache_hits.iter().rev() { - println!( - " {} - {} ({}%)", - q.name, - q.cache_hits, - q.cache_hits as f64 / (q.cache_hits + q.entry_count) as f64 - ); - } - } - - let mut query_value_count = queries.clone(); - query_value_count.sort_by_key(|q| q.entry_count); - println!("\nQuery value count:"); - for q in query_value_count.iter().rev() { - println!(" {} - {}", q.name, q.entry_count); - } - - let mut def_id_density: Vec<_> = - queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect(); - def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap()); - println!("\nLocal DefId density:"); - let total = tcx.hir().definitions().def_index_count() as f64; - for q in def_id_density.iter().rev() { - let local = q.local_def_id_keys.unwrap(); - println!(" {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total); - } -} - -macro_rules! print_stats { - (<$tcx:tt> $($category:tt { - $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)* - },)*) => { - fn query_stats(tcx: TyCtxt<'_>) -> Vec<QueryStats> { - let mut queries = Vec::new(); - - $($( - queries.push(stats::<queries::$name<'_>>( - stringify!($name), - &tcx.queries.$name, - )); - )*)* - - queries - } - } -} - -rustc_query_append! { [print_stats!][<'tcx>] } diff --git a/src/librustc/ty/query/values.rs b/src/librustc/ty/query/values.rs deleted file mode 100644 index b01d15c29b2..00000000000 --- a/src/librustc/ty/query/values.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::ty::{self, AdtSizedConstraint, Ty, TyCtxt}; - -use rustc_span::symbol::Symbol; - -pub(super) trait Value<'tcx>: Sized { - fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self; -} - -impl<'tcx, T> Value<'tcx> for T { - default fn from_cycle_error(tcx: TyCtxt<'tcx>) -> T { - tcx.sess.abort_if_errors(); - bug!("Value::from_cycle_error called without errors"); - } -} - -impl<'tcx> Value<'tcx> for Ty<'tcx> { - fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.types.err - } -} - -impl<'tcx> Value<'tcx> for ty::SymbolName { - fn from_cycle_error(_: TyCtxt<'tcx>) -> Self { - ty::SymbolName { name: Symbol::intern("<error>") } - } -} - -impl<'tcx> Value<'tcx> for AdtSizedConstraint<'tcx> { - fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { - AdtSizedConstraint(tcx.intern_type_list(&[tcx.types.err])) - } -} diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs deleted file mode 100644 index 3b9df72266f..00000000000 --- a/src/librustc/ty/relate.rs +++ /dev/null @@ -1,990 +0,0 @@ -//! Generalized type relating mechanism. -//! -//! A type relation `R` relates a pair of values `(A, B)`. `A and B` are usually -//! types or regions but can be other things. Examples of type relations are -//! subtyping, type equality, etc. - -use crate::mir::interpret::{get_slice_bytes, ConstValue}; -use crate::traits; -use crate::ty::error::{ExpectedFound, TypeError}; -use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_hir as ast; -use rustc_hir::def_id::DefId; -use rustc_target::spec::abi; -use std::iter; -use std::rc::Rc; - -pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>; - -#[derive(Clone, Debug)] -pub enum Cause { - ExistentialRegionBound, // relating an existential region bound -} - -pub trait TypeRelation<'tcx>: Sized { - fn tcx(&self) -> TyCtxt<'tcx>; - - fn param_env(&self) -> ty::ParamEnv<'tcx>; - - /// Returns a static string we can use for printouts. - fn tag(&self) -> &'static str; - - /// Returns `true` if the value `a` is the "expected" type in the - /// relation. Just affects error messages. - fn a_is_expected(&self) -> bool; - - fn with_cause<F, R>(&mut self, _cause: Cause, f: F) -> R - where - F: FnOnce(&mut Self) -> R, - { - f(self) - } - - /// Generic relation routine suitable for most anything. - fn relate<T: Relate<'tcx>>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> { - Relate::relate(self, a, b) - } - - /// Relate the two substitutions for the given item. The default - /// is to look up the variance for the item and proceed - /// accordingly. - fn relate_item_substs( - &mut self, - item_def_id: DefId, - a_subst: SubstsRef<'tcx>, - b_subst: SubstsRef<'tcx>, - ) -> RelateResult<'tcx, SubstsRef<'tcx>> { - debug!( - "relate_item_substs(item_def_id={:?}, a_subst={:?}, b_subst={:?})", - item_def_id, a_subst, b_subst - ); - - let opt_variances = self.tcx().variances_of(item_def_id); - relate_substs(self, Some(opt_variances), a_subst, b_subst) - } - - /// Switch variance for the purpose of relating `a` and `b`. - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - a: &T, - b: &T, - ) -> RelateResult<'tcx, T>; - - // Overrideable relations. You shouldn't typically call these - // directly, instead call `relate()`, which in turn calls - // these. This is both more uniform but also allows us to add - // additional hooks for other types in the future if needed - // without making older code, which called `relate`, obsolete. - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>; - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>>; - - fn consts( - &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>; - - fn binders<T>( - &mut self, - a: &ty::Binder<T>, - b: &ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> - where - T: Relate<'tcx>; -} - -pub trait Relate<'tcx>: TypeFoldable<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &Self, - b: &Self, - ) -> RelateResult<'tcx, Self>; -} - -/////////////////////////////////////////////////////////////////////////// -// Relate impls - -impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ty::TypeAndMut<'tcx>, - b: &ty::TypeAndMut<'tcx>, - ) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> { - debug!("{}.mts({:?}, {:?})", relation.tag(), a, b); - if a.mutbl != b.mutbl { - Err(TypeError::Mutability) - } else { - let mutbl = a.mutbl; - let variance = match mutbl { - ast::Mutability::Not => ty::Covariant, - ast::Mutability::Mut => ty::Invariant, - }; - let ty = relation.relate_with_variance(variance, &a.ty, &b.ty)?; - Ok(ty::TypeAndMut { ty, mutbl }) - } - } -} - -pub fn relate_substs<R: TypeRelation<'tcx>>( - relation: &mut R, - variances: Option<&[ty::Variance]>, - a_subst: SubstsRef<'tcx>, - b_subst: SubstsRef<'tcx>, -) -> RelateResult<'tcx, SubstsRef<'tcx>> { - let tcx = relation.tcx(); - - let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| { - let variance = variances.map_or(ty::Invariant, |v| v[i]); - relation.relate_with_variance(variance, a, b) - }); - - Ok(tcx.mk_substs(params)?) -} - -impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ty::FnSig<'tcx>, - b: &ty::FnSig<'tcx>, - ) -> RelateResult<'tcx, ty::FnSig<'tcx>> { - let tcx = relation.tcx(); - - if a.c_variadic != b.c_variadic { - return Err(TypeError::VariadicMismatch(expected_found( - relation, - &a.c_variadic, - &b.c_variadic, - ))); - } - let unsafety = relation.relate(&a.unsafety, &b.unsafety)?; - let abi = relation.relate(&a.abi, &b.abi)?; - - if a.inputs().len() != b.inputs().len() { - return Err(TypeError::ArgCount); - } - - let inputs_and_output = a - .inputs() - .iter() - .cloned() - .zip(b.inputs().iter().cloned()) - .map(|x| (x, false)) - .chain(iter::once(((a.output(), b.output()), true))) - .map(|((a, b), is_output)| { - if is_output { - relation.relate(&a, &b) - } else { - relation.relate_with_variance(ty::Contravariant, &a, &b) - } - }); - Ok(ty::FnSig { - inputs_and_output: tcx.mk_type_list(inputs_and_output)?, - c_variadic: a.c_variadic, - unsafety, - abi, - }) - } -} - -impl<'tcx> Relate<'tcx> for ast::Unsafety { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ast::Unsafety, - b: &ast::Unsafety, - ) -> RelateResult<'tcx, ast::Unsafety> { - if a != b { - Err(TypeError::UnsafetyMismatch(expected_found(relation, a, b))) - } else { - Ok(*a) - } - } -} - -impl<'tcx> Relate<'tcx> for abi::Abi { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &abi::Abi, - b: &abi::Abi, - ) -> RelateResult<'tcx, abi::Abi> { - if a == b { Ok(*a) } else { Err(TypeError::AbiMismatch(expected_found(relation, a, b))) } - } -} - -impl<'tcx> Relate<'tcx> for ty::ProjectionTy<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ty::ProjectionTy<'tcx>, - b: &ty::ProjectionTy<'tcx>, - ) -> RelateResult<'tcx, ty::ProjectionTy<'tcx>> { - if a.item_def_id != b.item_def_id { - Err(TypeError::ProjectionMismatched(expected_found( - relation, - &a.item_def_id, - &b.item_def_id, - ))) - } else { - let substs = relation.relate(&a.substs, &b.substs)?; - Ok(ty::ProjectionTy { item_def_id: a.item_def_id, substs: &substs }) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ty::ExistentialProjection<'tcx>, - b: &ty::ExistentialProjection<'tcx>, - ) -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> { - if a.item_def_id != b.item_def_id { - Err(TypeError::ProjectionMismatched(expected_found( - relation, - &a.item_def_id, - &b.item_def_id, - ))) - } else { - let ty = relation.relate(&a.ty, &b.ty)?; - let substs = relation.relate(&a.substs, &b.substs)?; - Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty }) - } - } -} - -impl<'tcx> Relate<'tcx> for Vec<ty::PolyExistentialProjection<'tcx>> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &Vec<ty::PolyExistentialProjection<'tcx>>, - b: &Vec<ty::PolyExistentialProjection<'tcx>>, - ) -> RelateResult<'tcx, Vec<ty::PolyExistentialProjection<'tcx>>> { - // To be compatible, `a` and `b` must be for precisely the - // same set of traits and item names. We always require that - // projection bounds lists are sorted by trait-def-id and item-name, - // so we can just iterate through the lists pairwise, so long as they are the - // same length. - if a.len() != b.len() { - Err(TypeError::ProjectionBoundsLength(expected_found(relation, &a.len(), &b.len()))) - } else { - a.iter().zip(b).map(|(a, b)| relation.relate(a, b)).collect() - } - } -} - -impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ty::TraitRef<'tcx>, - b: &ty::TraitRef<'tcx>, - ) -> RelateResult<'tcx, ty::TraitRef<'tcx>> { - // Different traits cannot be related. - if a.def_id != b.def_id { - Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id))) - } else { - let substs = relate_substs(relation, None, a.substs, b.substs)?; - Ok(ty::TraitRef { def_id: a.def_id, substs: substs }) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ty::ExistentialTraitRef<'tcx>, - b: &ty::ExistentialTraitRef<'tcx>, - ) -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> { - // Different traits cannot be related. - if a.def_id != b.def_id { - Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id))) - } else { - let substs = relate_substs(relation, None, a.substs, b.substs)?; - Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs: substs }) - } - } -} - -#[derive(Debug, Clone, TypeFoldable)] -struct GeneratorWitness<'tcx>(&'tcx ty::List<Ty<'tcx>>); - -impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &GeneratorWitness<'tcx>, - b: &GeneratorWitness<'tcx>, - ) -> RelateResult<'tcx, GeneratorWitness<'tcx>> { - assert_eq!(a.0.len(), b.0.len()); - let tcx = relation.tcx(); - let types = tcx.mk_type_list(a.0.iter().zip(b.0).map(|(a, b)| relation.relate(a, b)))?; - Ok(GeneratorWitness(types)) - } -} - -impl<'tcx> Relate<'tcx> for Ty<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &Ty<'tcx>, - b: &Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> { - relation.tys(a, b) - } -} - -/// The main "type relation" routine. Note that this does not handle -/// inference artifacts, so you should filter those out before calling -/// it. -pub fn super_relate_tys<R: TypeRelation<'tcx>>( - relation: &mut R, - a: Ty<'tcx>, - b: Ty<'tcx>, -) -> RelateResult<'tcx, Ty<'tcx>> { - let tcx = relation.tcx(); - debug!("super_relate_tys: a={:?} b={:?}", a, b); - match (&a.kind, &b.kind) { - (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - // The caller should handle these cases! - bug!("var types encountered in super_relate_tys") - } - - (ty::Bound(..), _) | (_, ty::Bound(..)) => { - bug!("bound types encountered in super_relate_tys") - } - - (&ty::Error, _) | (_, &ty::Error) => Ok(tcx.types.err), - - (&ty::Never, _) - | (&ty::Char, _) - | (&ty::Bool, _) - | (&ty::Int(_), _) - | (&ty::Uint(_), _) - | (&ty::Float(_), _) - | (&ty::Str, _) - if a == b => - { - Ok(a) - } - - (&ty::Param(ref a_p), &ty::Param(ref b_p)) if a_p.index == b_p.index => Ok(a), - - (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a), - - (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) if a_def == b_def => { - let substs = relation.relate_item_substs(a_def.did, a_substs, b_substs)?; - Ok(tcx.mk_adt(a_def, substs)) - } - - (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(tcx.mk_foreign(a_id)), - - (&ty::Dynamic(ref a_obj, ref a_region), &ty::Dynamic(ref b_obj, ref b_region)) => { - let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| { - relation.relate_with_variance(ty::Contravariant, a_region, b_region) - })?; - Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound)) - } - - (&ty::Generator(a_id, a_substs, movability), &ty::Generator(b_id, b_substs, _)) - if a_id == b_id => - { - // All Generator types with the same id represent - // the (anonymous) type of the same generator expression. So - // all of their regions should be equated. - let substs = relation.relate(&a_substs, &b_substs)?; - Ok(tcx.mk_generator(a_id, substs, movability)) - } - - (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => { - // Wrap our types with a temporary GeneratorWitness struct - // inside the binder so we can related them - let a_types = a_types.map_bound(GeneratorWitness); - let b_types = b_types.map_bound(GeneratorWitness); - // Then remove the GeneratorWitness for the result - let types = relation.relate(&a_types, &b_types)?.map_bound(|witness| witness.0); - Ok(tcx.mk_generator_witness(types)) - } - - (&ty::Closure(a_id, a_substs), &ty::Closure(b_id, b_substs)) if a_id == b_id => { - // All Closure types with the same id represent - // the (anonymous) type of the same closure expression. So - // all of their regions should be equated. - let substs = relation.relate(&a_substs, &b_substs)?; - Ok(tcx.mk_closure(a_id, &substs)) - } - - (&ty::RawPtr(ref a_mt), &ty::RawPtr(ref b_mt)) => { - let mt = relation.relate(a_mt, b_mt)?; - Ok(tcx.mk_ptr(mt)) - } - - (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => { - let r = relation.relate_with_variance(ty::Contravariant, &a_r, &b_r)?; - let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl }; - let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl }; - let mt = relation.relate(&a_mt, &b_mt)?; - Ok(tcx.mk_ref(r, mt)) - } - - (&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) => { - let t = relation.relate(&a_t, &b_t)?; - match relation.relate(&sz_a, &sz_b) { - Ok(sz) => Ok(tcx.mk_ty(ty::Array(t, sz))), - Err(err) => { - // Check whether the lengths are both concrete/known values, - // but are unequal, for better diagnostics. - let sz_a = sz_a.try_eval_usize(tcx, relation.param_env()); - let sz_b = sz_b.try_eval_usize(tcx, relation.param_env()); - match (sz_a, sz_b) { - (Some(sz_a_val), Some(sz_b_val)) => Err(TypeError::FixedArraySize( - expected_found(relation, &sz_a_val, &sz_b_val), - )), - _ => return Err(err), - } - } - } - } - - (&ty::Slice(a_t), &ty::Slice(b_t)) => { - let t = relation.relate(&a_t, &b_t)?; - Ok(tcx.mk_slice(t)) - } - - (&ty::Tuple(as_), &ty::Tuple(bs)) => { - if as_.len() == bs.len() { - Ok(tcx.mk_tup( - as_.iter() - .zip(bs) - .map(|(a, b)| relation.relate(&a.expect_ty(), &b.expect_ty())), - )?) - } else if !(as_.is_empty() || bs.is_empty()) { - Err(TypeError::TupleSize(expected_found(relation, &as_.len(), &bs.len()))) - } else { - Err(TypeError::Sorts(expected_found(relation, &a, &b))) - } - } - - (&ty::FnDef(a_def_id, a_substs), &ty::FnDef(b_def_id, b_substs)) - if a_def_id == b_def_id => - { - let substs = relation.relate_item_substs(a_def_id, a_substs, b_substs)?; - Ok(tcx.mk_fn_def(a_def_id, substs)) - } - - (&ty::FnPtr(a_fty), &ty::FnPtr(b_fty)) => { - let fty = relation.relate(&a_fty, &b_fty)?; - Ok(tcx.mk_fn_ptr(fty)) - } - - (ty::UnnormalizedProjection(a_data), ty::UnnormalizedProjection(b_data)) => { - let projection_ty = relation.relate(a_data, b_data)?; - Ok(tcx.mk_ty(ty::UnnormalizedProjection(projection_ty))) - } - - // these two are already handled downstream in case of lazy normalization - (ty::Projection(a_data), ty::Projection(b_data)) => { - let projection_ty = relation.relate(a_data, b_data)?; - Ok(tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs)) - } - - (&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs)) - if a_def_id == b_def_id => - { - let substs = relate_substs(relation, None, a_substs, b_substs)?; - Ok(tcx.mk_opaque(a_def_id, substs)) - } - - _ => Err(TypeError::Sorts(expected_found(relation, &a, &b))), - } -} - -/// The main "const relation" routine. Note that this does not handle -/// inference artifacts, so you should filter those out before calling -/// it. -pub fn super_relate_consts<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, -) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - let tcx = relation.tcx(); - - let eagerly_eval = |x: &'tcx ty::Const<'tcx>| { - if !x.val.has_local_value() { - return x.eval(tcx, relation.param_env()).val; - } - x.val - }; - - // Currently, the values that can be unified are primitive types, - // and those that derive both `PartialEq` and `Eq`, corresponding - // to `structural_match` types. - let new_const_val = match (eagerly_eval(a), eagerly_eval(b)) { - (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { - // The caller should handle these cases! - bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) - } - (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => { - return Ok(a); - } - (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) if p1 == p2 => { - return Ok(a); - } - (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => { - let new_val = match (a_val, b_val) { - (ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) if a.ty == b.ty => { - if a_val == b_val { - Ok(ConstValue::Scalar(a_val)) - } else if let ty::FnPtr(_) = a.ty.kind { - let alloc_map = tcx.alloc_map.lock(); - let a_instance = alloc_map.unwrap_fn(a_val.assert_ptr().alloc_id); - let b_instance = alloc_map.unwrap_fn(b_val.assert_ptr().alloc_id); - if a_instance == b_instance { - Ok(ConstValue::Scalar(a_val)) - } else { - Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) - } - } else { - Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) - } - } - - (a_val @ ConstValue::Slice { .. }, b_val @ ConstValue::Slice { .. }) => { - let a_bytes = get_slice_bytes(&tcx, a_val); - let b_bytes = get_slice_bytes(&tcx, b_val); - if a_bytes == b_bytes { - Ok(a_val) - } else { - Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) - } - } - - // FIXME(const_generics): handle `ConstValue::ByRef`. - _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))), - }; - - new_val.map(ty::ConstKind::Value) - } - - // FIXME(const_generics): this is wrong, as it is a projection - ( - ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted), - ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted), - ) if a_def_id == b_def_id && a_promoted == b_promoted => { - let substs = - relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?; - Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted)) - } - _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))), - }; - new_const_val.map(|val| tcx.mk_const(ty::Const { val, ty: a.ty })) -} - -impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &Self, - b: &Self, - ) -> RelateResult<'tcx, Self> { - if a.len() != b.len() { - return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))); - } - - let tcx = relation.tcx(); - let v = a.iter().zip(b.iter()).map(|(ep_a, ep_b)| { - use crate::ty::ExistentialPredicate::*; - match (*ep_a, *ep_b) { - (Trait(ref a), Trait(ref b)) => Ok(Trait(relation.relate(a, b)?)), - (Projection(ref a), Projection(ref b)) => Ok(Projection(relation.relate(a, b)?)), - (AutoTrait(ref a), AutoTrait(ref b)) if a == b => Ok(AutoTrait(*a)), - _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))), - } - }); - Ok(tcx.mk_existential_predicates(v)?) - } -} - -impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ty::ClosureSubsts<'tcx>, - b: &ty::ClosureSubsts<'tcx>, - ) -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> { - let substs = relate_substs(relation, None, a.substs, b.substs)?; - Ok(ty::ClosureSubsts { substs }) - } -} - -impl<'tcx> Relate<'tcx> for ty::GeneratorSubsts<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ty::GeneratorSubsts<'tcx>, - b: &ty::GeneratorSubsts<'tcx>, - ) -> RelateResult<'tcx, ty::GeneratorSubsts<'tcx>> { - let substs = relate_substs(relation, None, a.substs, b.substs)?; - Ok(ty::GeneratorSubsts { substs }) - } -} - -impl<'tcx> Relate<'tcx> for SubstsRef<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &SubstsRef<'tcx>, - b: &SubstsRef<'tcx>, - ) -> RelateResult<'tcx, SubstsRef<'tcx>> { - relate_substs(relation, None, a, b) - } -} - -impl<'tcx> Relate<'tcx> for ty::Region<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ty::Region<'tcx>, - b: &ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - relation.regions(*a, *b) - } -} - -impl<'tcx> Relate<'tcx> for &'tcx ty::Const<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &&'tcx ty::Const<'tcx>, - b: &&'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - relation.consts(*a, *b) - } -} - -impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder<T> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ty::Binder<T>, - b: &ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> { - relation.binders(a, b) - } -} - -impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for Rc<T> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &Rc<T>, - b: &Rc<T>, - ) -> RelateResult<'tcx, Rc<T>> { - let a: &T = a; - let b: &T = b; - Ok(Rc::new(relation.relate(a, b)?)) - } -} - -impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for Box<T> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &Box<T>, - b: &Box<T>, - ) -> RelateResult<'tcx, Box<T>> { - let a: &T = a; - let b: &T = b; - Ok(Box::new(relation.relate(a, b)?)) - } -} - -impl<'tcx> Relate<'tcx> for GenericArg<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &GenericArg<'tcx>, - b: &GenericArg<'tcx>, - ) -> RelateResult<'tcx, GenericArg<'tcx>> { - match (a.unpack(), b.unpack()) { - (GenericArgKind::Lifetime(a_lt), GenericArgKind::Lifetime(b_lt)) => { - Ok(relation.relate(&a_lt, &b_lt)?.into()) - } - (GenericArgKind::Type(a_ty), GenericArgKind::Type(b_ty)) => { - Ok(relation.relate(&a_ty, &b_ty)?.into()) - } - (GenericArgKind::Const(a_ct), GenericArgKind::Const(b_ct)) => { - Ok(relation.relate(&a_ct, &b_ct)?.into()) - } - (GenericArgKind::Lifetime(unpacked), x) => { - bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) - } - (GenericArgKind::Type(unpacked), x) => { - bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) - } - (GenericArgKind::Const(unpacked), x) => { - bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) - } - } - } -} - -impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ty::TraitPredicate<'tcx>, - b: &ty::TraitPredicate<'tcx>, - ) -> RelateResult<'tcx, ty::TraitPredicate<'tcx>> { - Ok(ty::TraitPredicate { trait_ref: relation.relate(&a.trait_ref, &b.trait_ref)? }) - } -} - -impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &ty::ProjectionPredicate<'tcx>, - b: &ty::ProjectionPredicate<'tcx>, - ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> { - Ok(ty::ProjectionPredicate { - projection_ty: relation.relate(&a.projection_ty, &b.projection_ty)?, - ty: relation.relate(&a.ty, &b.ty)?, - }) - } -} - -impl<'tcx> Relate<'tcx> for traits::WhereClause<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &traits::WhereClause<'tcx>, - b: &traits::WhereClause<'tcx>, - ) -> RelateResult<'tcx, traits::WhereClause<'tcx>> { - use crate::traits::WhereClause::*; - match (a, b) { - (Implemented(a_pred), Implemented(b_pred)) => { - Ok(Implemented(relation.relate(a_pred, b_pred)?)) - } - - (ProjectionEq(a_pred), ProjectionEq(b_pred)) => { - Ok(ProjectionEq(relation.relate(a_pred, b_pred)?)) - } - - (RegionOutlives(a_pred), RegionOutlives(b_pred)) => { - Ok(RegionOutlives(ty::OutlivesPredicate( - relation.relate(&a_pred.0, &b_pred.0)?, - relation.relate(&a_pred.1, &b_pred.1)?, - ))) - } - - (TypeOutlives(a_pred), TypeOutlives(b_pred)) => { - Ok(TypeOutlives(ty::OutlivesPredicate( - relation.relate(&a_pred.0, &b_pred.0)?, - relation.relate(&a_pred.1, &b_pred.1)?, - ))) - } - - _ => Err(TypeError::Mismatch), - } - } -} - -impl<'tcx> Relate<'tcx> for traits::WellFormed<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &traits::WellFormed<'tcx>, - b: &traits::WellFormed<'tcx>, - ) -> RelateResult<'tcx, traits::WellFormed<'tcx>> { - use crate::traits::WellFormed::*; - match (a, b) { - (Trait(a_pred), Trait(b_pred)) => Ok(Trait(relation.relate(a_pred, b_pred)?)), - (Ty(a_ty), Ty(b_ty)) => Ok(Ty(relation.relate(a_ty, b_ty)?)), - _ => Err(TypeError::Mismatch), - } - } -} - -impl<'tcx> Relate<'tcx> for traits::FromEnv<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &traits::FromEnv<'tcx>, - b: &traits::FromEnv<'tcx>, - ) -> RelateResult<'tcx, traits::FromEnv<'tcx>> { - use crate::traits::FromEnv::*; - match (a, b) { - (Trait(a_pred), Trait(b_pred)) => Ok(Trait(relation.relate(a_pred, b_pred)?)), - (Ty(a_ty), Ty(b_ty)) => Ok(Ty(relation.relate(a_ty, b_ty)?)), - _ => Err(TypeError::Mismatch), - } - } -} - -impl<'tcx> Relate<'tcx> for traits::DomainGoal<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &traits::DomainGoal<'tcx>, - b: &traits::DomainGoal<'tcx>, - ) -> RelateResult<'tcx, traits::DomainGoal<'tcx>> { - use crate::traits::DomainGoal::*; - match (a, b) { - (Holds(a_wc), Holds(b_wc)) => Ok(Holds(relation.relate(a_wc, b_wc)?)), - (WellFormed(a_wf), WellFormed(b_wf)) => Ok(WellFormed(relation.relate(a_wf, b_wf)?)), - (FromEnv(a_fe), FromEnv(b_fe)) => Ok(FromEnv(relation.relate(a_fe, b_fe)?)), - - (Normalize(a_pred), Normalize(b_pred)) => { - Ok(Normalize(relation.relate(a_pred, b_pred)?)) - } - - _ => Err(TypeError::Mismatch), - } - } -} - -impl<'tcx> Relate<'tcx> for traits::Goal<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &traits::Goal<'tcx>, - b: &traits::Goal<'tcx>, - ) -> RelateResult<'tcx, traits::Goal<'tcx>> { - use crate::traits::GoalKind::*; - match (a, b) { - (Implies(a_clauses, a_goal), Implies(b_clauses, b_goal)) => { - let clauses = relation.relate(a_clauses, b_clauses)?; - let goal = relation.relate(a_goal, b_goal)?; - Ok(relation.tcx().mk_goal(Implies(clauses, goal))) - } - - (And(a_left, a_right), And(b_left, b_right)) => { - let left = relation.relate(a_left, b_left)?; - let right = relation.relate(a_right, b_right)?; - Ok(relation.tcx().mk_goal(And(left, right))) - } - - (Not(a_goal), Not(b_goal)) => { - let goal = relation.relate(a_goal, b_goal)?; - Ok(relation.tcx().mk_goal(Not(goal))) - } - - (DomainGoal(a_goal), DomainGoal(b_goal)) => { - let goal = relation.relate(a_goal, b_goal)?; - Ok(relation.tcx().mk_goal(DomainGoal(goal))) - } - - (Quantified(a_qkind, a_goal), Quantified(b_qkind, b_goal)) if a_qkind == b_qkind => { - let goal = relation.relate(a_goal, b_goal)?; - Ok(relation.tcx().mk_goal(Quantified(*a_qkind, goal))) - } - - (CannotProve, CannotProve) => Ok(*a), - - _ => Err(TypeError::Mismatch), - } - } -} - -impl<'tcx> Relate<'tcx> for traits::Goals<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &traits::Goals<'tcx>, - b: &traits::Goals<'tcx>, - ) -> RelateResult<'tcx, traits::Goals<'tcx>> { - if a.len() != b.len() { - return Err(TypeError::Mismatch); - } - - let tcx = relation.tcx(); - let goals = a.iter().zip(b.iter()).map(|(a, b)| relation.relate(a, b)); - Ok(tcx.mk_goals(goals)?) - } -} - -impl<'tcx> Relate<'tcx> for traits::Clause<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &traits::Clause<'tcx>, - b: &traits::Clause<'tcx>, - ) -> RelateResult<'tcx, traits::Clause<'tcx>> { - use crate::traits::Clause::*; - match (a, b) { - (Implies(a_clause), Implies(b_clause)) => { - let clause = relation.relate(a_clause, b_clause)?; - Ok(Implies(clause)) - } - - (ForAll(a_clause), ForAll(b_clause)) => { - let clause = relation.relate(a_clause, b_clause)?; - Ok(ForAll(clause)) - } - - _ => Err(TypeError::Mismatch), - } - } -} - -impl<'tcx> Relate<'tcx> for traits::Clauses<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &traits::Clauses<'tcx>, - b: &traits::Clauses<'tcx>, - ) -> RelateResult<'tcx, traits::Clauses<'tcx>> { - if a.len() != b.len() { - return Err(TypeError::Mismatch); - } - - let tcx = relation.tcx(); - let clauses = a.iter().zip(b.iter()).map(|(a, b)| relation.relate(a, b)); - Ok(tcx.mk_clauses(clauses)?) - } -} - -impl<'tcx> Relate<'tcx> for traits::ProgramClause<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &traits::ProgramClause<'tcx>, - b: &traits::ProgramClause<'tcx>, - ) -> RelateResult<'tcx, traits::ProgramClause<'tcx>> { - Ok(traits::ProgramClause { - goal: relation.relate(&a.goal, &b.goal)?, - hypotheses: relation.relate(&a.hypotheses, &b.hypotheses)?, - category: traits::ProgramClauseCategory::Other, - }) - } -} - -impl<'tcx> Relate<'tcx> for traits::Environment<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &traits::Environment<'tcx>, - b: &traits::Environment<'tcx>, - ) -> RelateResult<'tcx, traits::Environment<'tcx>> { - Ok(traits::Environment { clauses: relation.relate(&a.clauses, &b.clauses)? }) - } -} - -impl<'tcx, G> Relate<'tcx> for traits::InEnvironment<'tcx, G> -where - G: Relate<'tcx>, -{ - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: &traits::InEnvironment<'tcx, G>, - b: &traits::InEnvironment<'tcx, G>, - ) -> RelateResult<'tcx, traits::InEnvironment<'tcx, G>> { - Ok(traits::InEnvironment { - environment: relation.relate(&a.environment, &b.environment)?, - goal: relation.relate(&a.goal, &b.goal)?, - }) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Error handling - -pub fn expected_found<R, T>(relation: &mut R, a: &T, b: &T) -> ExpectedFound<T> -where - R: TypeRelation<'tcx>, - T: Clone, -{ - expected_found_bool(relation.a_is_expected(), a, b) -} - -pub fn expected_found_bool<T>(a_is_expected: bool, a: &T, b: &T) -> ExpectedFound<T> -where - T: Clone, -{ - let a = a.clone(); - let b = b.clone(); - if a_is_expected { - ExpectedFound { expected: a, found: b } - } else { - ExpectedFound { expected: b, found: a } - } -} diff --git a/src/librustc/ty/steal.rs b/src/librustc/ty/steal.rs deleted file mode 100644 index 224e76845d7..00000000000 --- a/src/librustc/ty/steal.rs +++ /dev/null @@ -1,44 +0,0 @@ -use rustc_data_structures::sync::{MappedReadGuard, ReadGuard, RwLock}; - -/// The `Steal` struct is intended to used as the value for a query. -/// Specifically, we sometimes have queries (*cough* MIR *cough*) -/// where we create a large, complex value that we want to iteratively -/// update (e.g., optimize). We could clone the value for each -/// optimization, but that'd be expensive. And yet we don't just want -/// to mutate it in place, because that would spoil the idea that -/// queries are these pure functions that produce an immutable value -/// (since if you did the query twice, you could observe the mutations). -/// So instead we have the query produce a `&'tcx Steal<mir::Body<'tcx>>` -/// (to be very specific). Now we can read from this -/// as much as we want (using `borrow()`), but you can also -/// `steal()`. Once you steal, any further attempt to read will panic. -/// Therefore, we know that -- assuming no ICE -- nobody is observing -/// the fact that the MIR was updated. -/// -/// Obviously, whenever you have a query that yields a `Steal` value, -/// you must treat it with caution, and make sure that you know that -/// -- once the value is stolen -- it will never be read from again. -// -// FIXME(#41710): what is the best way to model linear queries? -pub struct Steal<T> { - value: RwLock<Option<T>>, -} - -impl<T> Steal<T> { - pub fn new(value: T) -> Self { - Steal { value: RwLock::new(Some(value)) } - } - - pub fn borrow(&self) -> MappedReadGuard<'_, T> { - ReadGuard::map(self.value.borrow(), |opt| match *opt { - None => bug!("attempted to read from stolen value"), - Some(ref v) => v, - }) - } - - pub fn steal(&self) -> T { - let value_ref = &mut *self.value.try_write().expect("stealing value which is locked"); - let value = value_ref.take(); - value.expect("attempt to read from stolen value") - } -} diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs deleted file mode 100644 index 03ff1b8a317..00000000000 --- a/src/librustc/ty/structural_impls.rs +++ /dev/null @@ -1,1084 +0,0 @@ -//! This module contains implements of the `Lift` and `TypeFoldable` -//! traits for various types in the Rust compiler. Most are written by -//! hand, though we've recently added some macros and proc-macros to help with the tedium. - -use crate::mir::interpret; -use crate::mir::ProjectionKind; -use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use crate::ty::print::{FmtPrinter, Printer}; -use crate::ty::{self, InferConst, Lift, Ty, TyCtxt}; -use rustc_hir as hir; -use rustc_hir::def::Namespace; -use rustc_hir::def_id::CRATE_DEF_INDEX; -use rustc_index::vec::{Idx, IndexVec}; - -use smallvec::SmallVec; -use std::fmt; -use std::rc::Rc; -use std::sync::Arc; - -impl fmt::Debug for ty::TraitDef { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ty::tls::with(|tcx| { - FmtPrinter::new(tcx, f, Namespace::TypeNS).print_def_path(self.def_id, &[])?; - Ok(()) - }) - } -} - -impl fmt::Debug for ty::AdtDef { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ty::tls::with(|tcx| { - FmtPrinter::new(tcx, f, Namespace::TypeNS).print_def_path(self.did, &[])?; - Ok(()) - }) - } -} - -impl fmt::Debug for ty::UpvarId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let name = ty::tls::with(|tcx| tcx.hir().name(self.var_path.hir_id)); - write!(f, "UpvarId({:?};`{}`;{:?})", self.var_path.hir_id, name, self.closure_expr_id) - } -} - -impl fmt::Debug for ty::UpvarBorrow<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "UpvarBorrow({:?}, {:?})", self.kind, self.region) - } -} - -impl fmt::Debug for ty::ExistentialTraitRef<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl fmt::Debug for ty::adjustment::Adjustment<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?} -> {}", self.kind, self.target) - } -} - -impl fmt::Debug for ty::BoundRegion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - ty::BrAnon(n) => write!(f, "BrAnon({:?})", n), - ty::BrNamed(did, name) => { - if did.index == CRATE_DEF_INDEX { - write!(f, "BrNamed({})", name) - } else { - write!(f, "BrNamed({:?}, {})", did, name) - } - } - ty::BrEnv => write!(f, "BrEnv"), - } - } -} - -impl fmt::Debug for ty::RegionKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - ty::ReEarlyBound(ref data) => write!(f, "ReEarlyBound({}, {})", data.index, data.name), - - ty::ReClosureBound(ref vid) => write!(f, "ReClosureBound({:?})", vid), - - ty::ReLateBound(binder_id, ref bound_region) => { - write!(f, "ReLateBound({:?}, {:?})", binder_id, bound_region) - } - - ty::ReFree(ref fr) => fr.fmt(f), - - ty::ReScope(id) => write!(f, "ReScope({:?})", id), - - ty::ReStatic => write!(f, "ReStatic"), - - ty::ReVar(ref vid) => vid.fmt(f), - - ty::RePlaceholder(placeholder) => write!(f, "RePlaceholder({:?})", placeholder), - - ty::ReEmpty(ui) => write!(f, "ReEmpty({:?})", ui), - - ty::ReErased => write!(f, "ReErased"), - } - } -} - -impl fmt::Debug for ty::FreeRegion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ReFree({:?}, {:?})", self.scope, self.bound_region) - } -} - -impl fmt::Debug for ty::Variance { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match *self { - ty::Covariant => "+", - ty::Contravariant => "-", - ty::Invariant => "o", - ty::Bivariant => "*", - }) - } -} - -impl fmt::Debug for ty::FnSig<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({:?}; c_variadic: {})->{:?}", self.inputs(), self.c_variadic, self.output()) - } -} - -impl fmt::Debug for ty::TyVid { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "_#{}t", self.index) - } -} - -impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "_#{}c", self.index) - } -} - -impl fmt::Debug for ty::IntVid { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "_#{}i", self.index) - } -} - -impl fmt::Debug for ty::FloatVid { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "_#{}f", self.index) - } -} - -impl fmt::Debug for ty::RegionVid { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "'_#{}r", self.index()) - } -} - -impl fmt::Debug for ty::InferTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - ty::TyVar(ref v) => v.fmt(f), - ty::IntVar(ref v) => v.fmt(f), - ty::FloatVar(ref v) => v.fmt(f), - ty::FreshTy(v) => write!(f, "FreshTy({:?})", v), - ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v), - ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v), - } - } -} - -impl fmt::Debug for ty::IntVarValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - ty::IntType(ref v) => v.fmt(f), - ty::UintType(ref v) => v.fmt(f), - } - } -} - -impl fmt::Debug for ty::FloatVarValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::Debug for ty::TraitRef<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl fmt::Debug for Ty<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl fmt::Debug for ty::ParamTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}/#{}", self.name, self.index) - } -} - -impl fmt::Debug for ty::ParamConst { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}/#{}", self.name, self.index) - } -} - -impl fmt::Debug for ty::TraitPredicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "TraitPredicate({:?})", self.trait_ref) - } -} - -impl fmt::Debug for ty::ProjectionPredicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.ty) - } -} - -impl fmt::Debug for ty::Predicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - ty::Predicate::Trait(ref a, constness) => { - if let hir::Constness::Const = constness { - write!(f, "const ")?; - } - a.fmt(f) - } - ty::Predicate::Subtype(ref pair) => pair.fmt(f), - ty::Predicate::RegionOutlives(ref pair) => pair.fmt(f), - ty::Predicate::TypeOutlives(ref pair) => pair.fmt(f), - ty::Predicate::Projection(ref pair) => pair.fmt(f), - ty::Predicate::WellFormed(ty) => write!(f, "WellFormed({:?})", ty), - ty::Predicate::ObjectSafe(trait_def_id) => write!(f, "ObjectSafe({:?})", trait_def_id), - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind) - } - ty::Predicate::ConstEvaluatable(def_id, substs) => { - write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) - } - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Atomic structs -// -// For things that don't carry any arena-allocated data (and are -// copy...), just add them to this list. - -CloneTypeFoldableAndLiftImpls! { - (), - bool, - usize, - crate::ty::layout::VariantIdx, - u64, - String, - crate::middle::region::Scope, - ::syntax::ast::FloatTy, - ::syntax::ast::NodeId, - ::rustc_span::symbol::Symbol, - ::rustc_hir::def::Res, - ::rustc_hir::def_id::DefId, - ::rustc_hir::InlineAsmInner, - ::rustc_hir::MatchSource, - ::rustc_hir::Mutability, - ::rustc_hir::Unsafety, - ::rustc_target::spec::abi::Abi, - crate::mir::Local, - crate::mir::Promoted, - crate::traits::Reveal, - crate::ty::adjustment::AutoBorrowMutability, - crate::ty::AdtKind, - // Including `BoundRegion` is a *bit* dubious, but direct - // references to bound region appear in `ty::Error`, and aren't - // really meant to be folded. In general, we can only fold a fully - // general `Region`. - crate::ty::BoundRegion, - crate::ty::Placeholder<crate::ty::BoundRegion>, - crate::ty::ClosureKind, - crate::ty::FreeRegion, - crate::ty::InferTy, - crate::ty::IntVarValue, - crate::ty::ParamConst, - crate::ty::ParamTy, - crate::ty::adjustment::PointerCast, - crate::ty::RegionVid, - crate::ty::UniverseIndex, - crate::ty::Variance, - ::rustc_span::Span, -} - -/////////////////////////////////////////////////////////////////////////// -// Lift implementations - -// FIXME(eddyb) replace all the uses of `Option::map` with `?`. -impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) { - type Lifted = (A::Lifted, B::Lifted); - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.0).and_then(|a| tcx.lift(&self.1).map(|b| (a, b))) - } -} - -impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>, C: Lift<'tcx>> Lift<'tcx> for (A, B, C) { - type Lifted = (A::Lifted, B::Lifted, C::Lifted); - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.0) - .and_then(|a| tcx.lift(&self.1).and_then(|b| tcx.lift(&self.2).map(|c| (a, b, c)))) - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> { - type Lifted = Option<T::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match *self { - Some(ref x) => tcx.lift(x).map(Some), - None => Some(None), - } - } -} - -impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result<T, E> { - type Lifted = Result<T::Lifted, E::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match *self { - Ok(ref x) => tcx.lift(x).map(Ok), - Err(ref e) => tcx.lift(e).map(Err), - } - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box<T> { - type Lifted = Box<T::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&**self).map(Box::new) - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Rc<T> { - type Lifted = Rc<T::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&**self).map(Rc::new) - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Arc<T> { - type Lifted = Arc<T::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&**self).map(Arc::new) - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] { - type Lifted = Vec<T::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - // type annotation needed to inform `projection_must_outlive` - let mut result: Vec<<T as Lift<'tcx>>::Lifted> = Vec::with_capacity(self.len()); - for x in self { - if let Some(value) = tcx.lift(x) { - result.push(value); - } else { - return None; - } - } - Some(result) - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Vec<T> { - type Lifted = Vec<T::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self[..]) - } -} - -impl<'tcx, I: Idx, T: Lift<'tcx>> Lift<'tcx> for IndexVec<I, T> { - type Lifted = IndexVec<I, T::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - self.iter().map(|e| tcx.lift(e)).collect() - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> { - type Lifted = ty::TraitRef<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.substs).map(|substs| ty::TraitRef { def_id: self.def_id, substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialTraitRef<'a> { - type Lifted = ty::ExistentialTraitRef<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.substs).map(|substs| ty::ExistentialTraitRef { def_id: self.def_id, substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> { - type Lifted = ty::ExistentialPredicate<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match self { - ty::ExistentialPredicate::Trait(x) => tcx.lift(x).map(ty::ExistentialPredicate::Trait), - ty::ExistentialPredicate::Projection(x) => { - tcx.lift(x).map(ty::ExistentialPredicate::Projection) - } - ty::ExistentialPredicate::AutoTrait(def_id) => { - Some(ty::ExistentialPredicate::AutoTrait(*def_id)) - } - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> { - type Lifted = ty::TraitPredicate<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> { - tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate { trait_ref }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> { - type Lifted = ty::SubtypePredicate<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<ty::SubtypePredicate<'tcx>> { - tcx.lift(&(self.a, self.b)).map(|(a, b)| ty::SubtypePredicate { - a_is_expected: self.a_is_expected, - a, - b, - }) - } -} - -impl<'tcx, A: Copy + Lift<'tcx>, B: Copy + Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate<A, B> { - type Lifted = ty::OutlivesPredicate<A::Lifted, B::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&(self.0, self.1)).map(|(a, b)| ty::OutlivesPredicate(a, b)) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionTy<'a> { - type Lifted = ty::ProjectionTy<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionTy<'tcx>> { - tcx.lift(&self.substs) - .map(|substs| ty::ProjectionTy { item_def_id: self.item_def_id, substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> { - type Lifted = ty::ProjectionPredicate<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> { - tcx.lift(&(self.projection_ty, self.ty)) - .map(|(projection_ty, ty)| ty::ProjectionPredicate { projection_ty, ty }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> { - type Lifted = ty::ExistentialProjection<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.substs).map(|substs| ty::ExistentialProjection { - substs, - ty: tcx.lift(&self.ty).expect("type must lift when substs do"), - item_def_id: self.item_def_id, - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { - type Lifted = ty::Predicate<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match *self { - ty::Predicate::Trait(ref binder, constness) => { - tcx.lift(binder).map(|binder| ty::Predicate::Trait(binder, constness)) - } - ty::Predicate::Subtype(ref binder) => tcx.lift(binder).map(ty::Predicate::Subtype), - ty::Predicate::RegionOutlives(ref binder) => { - tcx.lift(binder).map(ty::Predicate::RegionOutlives) - } - ty::Predicate::TypeOutlives(ref binder) => { - tcx.lift(binder).map(ty::Predicate::TypeOutlives) - } - ty::Predicate::Projection(ref binder) => { - tcx.lift(binder).map(ty::Predicate::Projection) - } - ty::Predicate::WellFormed(ty) => tcx.lift(&ty).map(ty::Predicate::WellFormed), - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - tcx.lift(&closure_substs).map(|closure_substs| { - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) - }) - } - ty::Predicate::ObjectSafe(trait_def_id) => { - Some(ty::Predicate::ObjectSafe(trait_def_id)) - } - ty::Predicate::ConstEvaluatable(def_id, substs) => { - tcx.lift(&substs).map(|substs| ty::Predicate::ConstEvaluatable(def_id, substs)) - } - } - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> { - type Lifted = ty::Binder<T::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(self.skip_binder()).map(ty::Binder::bind) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { - type Lifted = ty::ParamEnv<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.caller_bounds).map(|caller_bounds| ty::ParamEnv { - reveal: self.reveal, - caller_bounds, - def_id: self.def_id, - }) - } -} - -impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::ParamEnvAnd<'a, T> { - type Lifted = ty::ParamEnvAnd<'tcx, T::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.param_env).and_then(|param_env| { - tcx.lift(&self.value).map(|value| ty::ParamEnvAnd { param_env, value }) - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { - type Lifted = ty::ClosureSubsts<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.substs).map(|substs| ty::ClosureSubsts { substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::GeneratorSubsts<'a> { - type Lifted = ty::GeneratorSubsts<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.substs).map(|substs| ty::GeneratorSubsts { substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> { - type Lifted = ty::adjustment::Adjustment<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.kind).and_then(|kind| { - tcx.lift(&self.target).map(|target| ty::adjustment::Adjustment { kind, target }) - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { - type Lifted = ty::adjustment::Adjust<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match *self { - ty::adjustment::Adjust::NeverToAny => Some(ty::adjustment::Adjust::NeverToAny), - ty::adjustment::Adjust::Pointer(ptr) => Some(ty::adjustment::Adjust::Pointer(ptr)), - ty::adjustment::Adjust::Deref(ref overloaded) => { - tcx.lift(overloaded).map(ty::adjustment::Adjust::Deref) - } - ty::adjustment::Adjust::Borrow(ref autoref) => { - tcx.lift(autoref).map(ty::adjustment::Adjust::Borrow) - } - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> { - type Lifted = ty::adjustment::OverloadedDeref<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.region) - .map(|region| ty::adjustment::OverloadedDeref { region, mutbl: self.mutbl }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { - type Lifted = ty::adjustment::AutoBorrow<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match *self { - ty::adjustment::AutoBorrow::Ref(r, m) => { - tcx.lift(&r).map(|r| ty::adjustment::AutoBorrow::Ref(r, m)) - } - ty::adjustment::AutoBorrow::RawPtr(m) => Some(ty::adjustment::AutoBorrow::RawPtr(m)), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::GenSig<'a> { - type Lifted = ty::GenSig<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&(self.resume_ty, self.yield_ty, self.return_ty)) - .map(|(resume_ty, yield_ty, return_ty)| ty::GenSig { resume_ty, yield_ty, return_ty }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> { - type Lifted = ty::FnSig<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.inputs_and_output).map(|x| ty::FnSig { - inputs_and_output: x, - c_variadic: self.c_variadic, - unsafety: self.unsafety, - abi: self.abi, - }) - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound<T> { - type Lifted = ty::error::ExpectedFound<T::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.expected).and_then(|expected| { - tcx.lift(&self.found).map(|found| ty::error::ExpectedFound { expected, found }) - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { - type Lifted = ty::error::TypeError<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - use crate::ty::error::TypeError::*; - - Some(match *self { - Mismatch => Mismatch, - UnsafetyMismatch(x) => UnsafetyMismatch(x), - AbiMismatch(x) => AbiMismatch(x), - Mutability => Mutability, - TupleSize(x) => TupleSize(x), - FixedArraySize(x) => FixedArraySize(x), - ArgCount => ArgCount, - RegionsDoesNotOutlive(a, b) => { - return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b)); - } - RegionsInsufficientlyPolymorphic(a, b) => { - return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b)); - } - RegionsOverlyPolymorphic(a, b) => { - return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b)); - } - RegionsPlaceholderMismatch => RegionsPlaceholderMismatch, - IntMismatch(x) => IntMismatch(x), - FloatMismatch(x) => FloatMismatch(x), - Traits(x) => Traits(x), - VariadicMismatch(x) => VariadicMismatch(x), - CyclicTy(t) => return tcx.lift(&t).map(|t| CyclicTy(t)), - ProjectionMismatched(x) => ProjectionMismatched(x), - ProjectionBoundsLength(x) => ProjectionBoundsLength(x), - Sorts(ref x) => return tcx.lift(x).map(Sorts), - ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), - ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch), - IntrinsicCast => IntrinsicCast, - ObjectUnsafeCoercion(ref x) => return tcx.lift(x).map(ObjectUnsafeCoercion), - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { - type Lifted = ty::InstanceDef<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match *self { - ty::InstanceDef::Item(def_id) => Some(ty::InstanceDef::Item(def_id)), - ty::InstanceDef::VtableShim(def_id) => Some(ty::InstanceDef::VtableShim(def_id)), - ty::InstanceDef::ReifyShim(def_id) => Some(ty::InstanceDef::ReifyShim(def_id)), - ty::InstanceDef::Intrinsic(def_id) => Some(ty::InstanceDef::Intrinsic(def_id)), - ty::InstanceDef::FnPtrShim(def_id, ref ty) => { - Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?)) - } - ty::InstanceDef::Virtual(def_id, n) => Some(ty::InstanceDef::Virtual(def_id, n)), - ty::InstanceDef::ClosureOnceShim { call_once } => { - Some(ty::InstanceDef::ClosureOnceShim { call_once }) - } - ty::InstanceDef::DropGlue(def_id, ref ty) => { - Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?)) - } - ty::InstanceDef::CloneShim(def_id, ref ty) => { - Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?)) - } - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// TypeFoldable implementations. -// -// Ideally, each type should invoke `folder.fold_foo(self)` and -// nothing else. In some cases, though, we haven't gotten around to -// adding methods on the `folder` yet, and thus the folding is -// hard-coded here. This is less-flexible, because folders cannot -// override the behavior, but there are a lot of random types and one -// can easily refactor the folding into the TypeFolder trait as -// needed. - -/// AdtDefs are basically the same as a DefId. -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self { - *self - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool { - false - } -} - -impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) { - (self.0.fold_with(folder), self.1.fold_with(folder)) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.0.visit_with(visitor) || self.1.visit_with(visitor) - } -} - -EnumTypeFoldableImpl! { - impl<'tcx, T> TypeFoldable<'tcx> for Option<T> { - (Some)(a), - (None), - } where T: TypeFoldable<'tcx> -} - -EnumTypeFoldableImpl! { - impl<'tcx, T, E> TypeFoldable<'tcx> for Result<T, E> { - (Ok)(a), - (Err)(a), - } where T: TypeFoldable<'tcx>, E: TypeFoldable<'tcx>, -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - Rc::new((**self).fold_with(folder)) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - (**self).visit_with(visitor) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - Arc::new((**self).fold_with(folder)) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - (**self).visit_with(visitor) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let content: T = (**self).fold_with(folder); - box content - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - (**self).visit_with(visitor) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect() - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>().into_boxed_slice() - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - self.map_bound_ref(|ty| ty.fold_with(folder)) - } - - fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_binder(self) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.skip_binder().visit_with(visitor) - } - - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - visitor.visit_binder(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - fold_list(*self, folder, |tcx, v| tcx.intern_existential_predicates(v)) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|p| p.visit_with(visitor)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - fold_list(*self, folder, |tcx, v| tcx.intern_type_list(v)) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - fold_list(*self, folder, |tcx, v| tcx.intern_projs(v)) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - use crate::ty::InstanceDef::*; - Self { - substs: self.substs.fold_with(folder), - def: match self.def { - Item(did) => Item(did.fold_with(folder)), - VtableShim(did) => VtableShim(did.fold_with(folder)), - ReifyShim(did) => ReifyShim(did.fold_with(folder)), - Intrinsic(did) => Intrinsic(did.fold_with(folder)), - FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder), ty.fold_with(folder)), - Virtual(did, i) => Virtual(did.fold_with(folder), i), - ClosureOnceShim { call_once } => { - ClosureOnceShim { call_once: call_once.fold_with(folder) } - } - DropGlue(did, ty) => DropGlue(did.fold_with(folder), ty.fold_with(folder)), - CloneShim(did, ty) => CloneShim(did.fold_with(folder), ty.fold_with(folder)), - }, - } - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - use crate::ty::InstanceDef::*; - self.substs.visit_with(visitor) - || match self.def { - Item(did) | VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { - did.visit_with(visitor) - } - FnPtrShim(did, ty) | CloneShim(did, ty) => { - did.visit_with(visitor) || ty.visit_with(visitor) - } - DropGlue(did, ty) => did.visit_with(visitor) || ty.visit_with(visitor), - ClosureOnceShim { call_once } => call_once.visit_with(visitor), - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - Self { instance: self.instance.fold_with(folder), promoted: self.promoted } - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.instance.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let kind = match self.kind { - ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)), - ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)), - ty::Slice(typ) => ty::Slice(typ.fold_with(folder)), - ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)), - ty::Dynamic(ref trait_ty, ref region) => { - ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder)) - } - ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)), - ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)), - ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)), - ty::Ref(ref r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl), - ty::Generator(did, substs, movability) => { - ty::Generator(did, substs.fold_with(folder), movability) - } - ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)), - ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)), - ty::Projection(ref data) => ty::Projection(data.fold_with(folder)), - ty::UnnormalizedProjection(ref data) => { - ty::UnnormalizedProjection(data.fold_with(folder)) - } - ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)), - - ty::Bool - | ty::Char - | ty::Str - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Error - | ty::Infer(_) - | ty::Param(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Never - | ty::Foreign(..) => return self, - }; - - if self.kind == kind { self } else { folder.tcx().mk_ty(kind) } - } - - fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_ty(*self) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - match self.kind { - ty::RawPtr(ref tm) => tm.visit_with(visitor), - ty::Array(typ, sz) => typ.visit_with(visitor) || sz.visit_with(visitor), - ty::Slice(typ) => typ.visit_with(visitor), - ty::Adt(_, substs) => substs.visit_with(visitor), - ty::Dynamic(ref trait_ty, ref reg) => { - trait_ty.visit_with(visitor) || reg.visit_with(visitor) - } - ty::Tuple(ts) => ts.visit_with(visitor), - ty::FnDef(_, substs) => substs.visit_with(visitor), - ty::FnPtr(ref f) => f.visit_with(visitor), - ty::Ref(r, ty, _) => r.visit_with(visitor) || ty.visit_with(visitor), - ty::Generator(_did, ref substs, _) => substs.visit_with(visitor), - ty::GeneratorWitness(ref types) => types.visit_with(visitor), - ty::Closure(_did, ref substs) => substs.visit_with(visitor), - ty::Projection(ref data) | ty::UnnormalizedProjection(ref data) => { - data.visit_with(visitor) - } - ty::Opaque(_, ref substs) => substs.visit_with(visitor), - - ty::Bool - | ty::Char - | ty::Str - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Error - | ty::Infer(_) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Param(..) - | ty::Never - | ty::Foreign(..) => false, - } - } - - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - visitor.visit_ty(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self { - *self - } - - fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_region(*self) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool { - false - } - - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - visitor.visit_region(*self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v)) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|p| p.visit_with(visitor)) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - self.iter().map(|x| x.fold_with(folder)).collect() - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let ty = self.ty.fold_with(folder); - let val = self.val.fold_with(folder); - folder.tcx().mk_const(ty::Const { ty, val }) - } - - fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_const(*self) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.ty.visit_with(visitor) || self.val.visit_with(visitor) - } - - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - visitor.visit_const(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - match *self { - ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)), - ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)), - ty::ConstKind::Unevaluated(did, substs, promoted) => { - ty::ConstKind::Unevaluated(did, substs.fold_with(folder), promoted) - } - ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) => { - *self - } - } - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - match *self { - ty::ConstKind::Infer(ic) => ic.visit_with(visitor), - ty::ConstKind::Param(p) => p.visit_with(visitor), - ty::ConstKind::Unevaluated(_, substs, _) => substs.visit_with(visitor), - ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { - false - } - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self { - *self - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool { - false - } -} - -// Does the equivalent of -// ``` -// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); -// folder.tcx().intern_*(&v) -// ``` -fn fold_list<'tcx, F, T>( - list: &'tcx ty::List<T>, - folder: &mut F, - intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>, -) -> &'tcx ty::List<T> -where - F: TypeFolder<'tcx>, - T: TypeFoldable<'tcx> + PartialEq + Copy, -{ - let mut iter = list.iter(); - // Look for the first element that changed - if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| { - let new_t = t.fold_with(folder); - if new_t == *t { None } else { Some((i, new_t)) } - }) { - // An element changed, prepare to intern the resulting list - let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len()); - new_list.extend_from_slice(&list[..i]); - new_list.push(new_t); - new_list.extend(iter.map(|t| t.fold_with(folder))); - intern(folder.tcx(), &new_list) - } else { - list - } -} diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs deleted file mode 100644 index c3698f402a9..00000000000 --- a/src/librustc/ty/sty.rs +++ /dev/null @@ -1,2602 +0,0 @@ -//! This module contains `TyKind` and its major components. - -#![allow(rustc::usage_of_ty_tykind)] - -use self::InferTy::*; -use self::TyKind::*; - -use crate::infer::canonical::Canonical; -use crate::middle::region; -use crate::mir::interpret::ConstValue; -use crate::mir::interpret::Scalar; -use crate::mir::Promoted; -use crate::ty::layout::VariantIdx; -use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; -use crate::ty::{ - self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness, -}; -use crate::ty::{List, ParamEnv, ParamEnvAnd, TyS}; -use polonius_engine::Atom; -use rustc_data_structures::captures::Captures; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_index::vec::Idx; -use rustc_macros::HashStable; -use rustc_span::symbol::{kw, Symbol}; -use rustc_target::spec::abi; -use smallvec::SmallVec; -use std::borrow::Cow; -use std::cmp::Ordering; -use std::marker::PhantomData; -use std::ops::Range; -use syntax::ast::{self, Ident}; - -#[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Debug, - RustcEncodable, - RustcDecodable, - HashStable, - TypeFoldable, - Lift -)] -pub struct TypeAndMut<'tcx> { - pub ty: Ty<'tcx>, - pub mutbl: hir::Mutability, -} - -#[derive( - Clone, - PartialEq, - PartialOrd, - Eq, - Ord, - Hash, - RustcEncodable, - RustcDecodable, - Copy, - HashStable -)] -/// A "free" region `fr` can be interpreted as "some region -/// at least as big as the scope `fr.scope`". -pub struct FreeRegion { - pub scope: DefId, - pub bound_region: BoundRegion, -} - -#[derive( - Clone, - PartialEq, - PartialOrd, - Eq, - Ord, - Hash, - RustcEncodable, - RustcDecodable, - Copy, - HashStable -)] -pub enum BoundRegion { - /// An anonymous region parameter for a given fn (&T) - BrAnon(u32), - - /// Named region parameters for functions (a in &'a T) - /// - /// The `DefId` is needed to distinguish free regions in - /// the event of shadowing. - BrNamed(DefId, Symbol), - - /// Anonymous region for the implicit env pointer parameter - /// to a closure - BrEnv, -} - -impl BoundRegion { - pub fn is_named(&self) -> bool { - match *self { - BoundRegion::BrNamed(_, name) => name != kw::UnderscoreLifetime, - _ => false, - } - } - - /// When canonicalizing, we replace unbound inference variables and free - /// regions with anonymous late bound regions. This method asserts that - /// we have an anonymous late bound region, which hence may refer to - /// a canonical variable. - pub fn assert_bound_var(&self) -> BoundVar { - match *self { - BoundRegion::BrAnon(var) => BoundVar::from_u32(var), - _ => bug!("bound region is not anonymous"), - } - } -} - -/// N.B., if you change this, you'll probably want to change the corresponding -/// AST structure in `libsyntax/ast.rs` as well. -#[derive( - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - RustcEncodable, - RustcDecodable, - HashStable, - Debug -)] -#[rustc_diagnostic_item = "TyKind"] -pub enum TyKind<'tcx> { - /// The primitive boolean type. Written as `bool`. - Bool, - - /// The primitive character type; holds a Unicode scalar value - /// (a non-surrogate code point). Written as `char`. - Char, - - /// A primitive signed integer type. For example, `i32`. - Int(ast::IntTy), - - /// A primitive unsigned integer type. For example, `u32`. - Uint(ast::UintTy), - - /// A primitive floating-point type. For example, `f64`. - Float(ast::FloatTy), - - /// Structures, enumerations and unions. - /// - /// InternalSubsts here, possibly against intuition, *may* contain `Param`s. - /// That is, even after substitution it is possible that there are type - /// variables. This happens when the `Adt` corresponds to an ADT - /// definition and not a concrete use of it. - Adt(&'tcx AdtDef, SubstsRef<'tcx>), - - /// An unsized FFI type that is opaque to Rust. Written as `extern type T`. - Foreign(DefId), - - /// The pointee of a string slice. Written as `str`. - Str, - - /// An array with the given length. Written as `[T; n]`. - Array(Ty<'tcx>, &'tcx ty::Const<'tcx>), - - /// The pointee of an array slice. Written as `[T]`. - Slice(Ty<'tcx>), - - /// A raw pointer. Written as `*mut T` or `*const T` - RawPtr(TypeAndMut<'tcx>), - - /// A reference; a pointer with an associated lifetime. Written as - /// `&'a mut T` or `&'a T`. - Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability), - - /// The anonymous type of a function declaration/definition. Each - /// function has a unique type, which is output (for a function - /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`. - /// - /// For example the type of `bar` here: - /// - /// ```rust - /// fn foo() -> i32 { 1 } - /// let bar = foo; // bar: fn() -> i32 {foo} - /// ``` - FnDef(DefId, SubstsRef<'tcx>), - - /// A pointer to a function. Written as `fn() -> i32`. - /// - /// For example the type of `bar` here: - /// - /// ```rust - /// fn foo() -> i32 { 1 } - /// let bar: fn() -> i32 = foo; - /// ``` - FnPtr(PolyFnSig<'tcx>), - - /// A trait, defined with `trait`. - Dynamic(Binder<&'tcx List<ExistentialPredicate<'tcx>>>, ty::Region<'tcx>), - - /// The anonymous type of a closure. Used to represent the type of - /// `|a| a`. - Closure(DefId, SubstsRef<'tcx>), - - /// The anonymous type of a generator. Used to represent the type of - /// `|a| yield a`. - Generator(DefId, SubstsRef<'tcx>, hir::Movability), - - /// A type representin the types stored inside a generator. - /// This should only appear in GeneratorInteriors. - GeneratorWitness(Binder<&'tcx List<Ty<'tcx>>>), - - /// The never type `!` - Never, - - /// A tuple type. For example, `(i32, bool)`. - /// Use `TyS::tuple_fields` to iterate over the field types. - Tuple(SubstsRef<'tcx>), - - /// The projection of an associated type. For example, - /// `<T as Trait<..>>::N`. - Projection(ProjectionTy<'tcx>), - - /// A placeholder type used when we do not have enough information - /// to normalize the projection of an associated type to an - /// existing concrete type. Currently only used with chalk-engine. - UnnormalizedProjection(ProjectionTy<'tcx>), - - /// Opaque (`impl Trait`) type found in a return type. - /// The `DefId` comes either from - /// * the `impl Trait` ast::Ty node, - /// * or the `type Foo = impl Trait` declaration - /// The substitutions are for the generics of the function in question. - /// After typeck, the concrete type can be found in the `types` map. - Opaque(DefId, SubstsRef<'tcx>), - - /// A type parameter; for example, `T` in `fn f<T>(x: T) {} - Param(ParamTy), - - /// Bound type variable, used only when preparing a trait query. - Bound(ty::DebruijnIndex, BoundTy), - - /// A placeholder type - universally quantified higher-ranked type. - Placeholder(ty::PlaceholderType), - - /// A type variable used during type checking. - Infer(InferTy), - - /// A placeholder for a type which could not be computed; this is - /// propagated to avoid useless error messages. - Error, -} - -// `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(target_arch = "x86_64")] -static_assert_size!(TyKind<'_>, 24); - -/// A closure can be modeled as a struct that looks like: -/// -/// struct Closure<'l0...'li, T0...Tj, CK, CS, U0...Uk> { -/// upvar0: U0, -/// ... -/// upvark: Uk -/// } -/// -/// where: -/// -/// - 'l0...'li and T0...Tj are the lifetime and type parameters -/// in scope on the function that defined the closure, -/// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This -/// is rather hackily encoded via a scalar type. See -/// `TyS::to_opt_closure_kind` for details. -/// - CS represents the *closure signature*, representing as a `fn()` -/// type. For example, `fn(u32, u32) -> u32` would mean that the closure -/// implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait -/// specified above. -/// - U0...Uk are type parameters representing the types of its upvars -/// (borrowed, if appropriate; that is, if Ui represents a by-ref upvar, -/// and the up-var has the type `Foo`, then `Ui = &Foo`). -/// -/// So, for example, given this function: -/// -/// fn foo<'a, T>(data: &'a mut T) { -/// do(|| data.count += 1) -/// } -/// -/// the type of the closure would be something like: -/// -/// struct Closure<'a, T, U0> { -/// data: U0 -/// } -/// -/// Note that the type of the upvar is not specified in the struct. -/// You may wonder how the impl would then be able to use the upvar, -/// if it doesn't know it's type? The answer is that the impl is -/// (conceptually) not fully generic over Closure but rather tied to -/// instances with the expected upvar types: -/// -/// impl<'b, 'a, T> FnMut() for Closure<'a, T, &'b mut &'a mut T> { -/// ... -/// } -/// -/// You can see that the *impl* fully specified the type of the upvar -/// and thus knows full well that `data` has type `&'b mut &'a mut T`. -/// (Here, I am assuming that `data` is mut-borrowed.) -/// -/// Now, the last question you may ask is: Why include the upvar types -/// as extra type parameters? The reason for this design is that the -/// upvar types can reference lifetimes that are internal to the -/// creating function. In my example above, for example, the lifetime -/// `'b` represents the scope of the closure itself; this is some -/// subset of `foo`, probably just the scope of the call to the to -/// `do()`. If we just had the lifetime/type parameters from the -/// enclosing function, we couldn't name this lifetime `'b`. Note that -/// there can also be lifetimes in the types of the upvars themselves, -/// if one of them happens to be a reference to something that the -/// creating fn owns. -/// -/// OK, you say, so why not create a more minimal set of parameters -/// that just includes the extra lifetime parameters? The answer is -/// primarily that it would be hard --- we don't know at the time when -/// we create the closure type what the full types of the upvars are, -/// nor do we know which are borrowed and which are not. In this -/// design, we can just supply a fresh type parameter and figure that -/// out later. -/// -/// All right, you say, but why include the type parameters from the -/// original function then? The answer is that codegen may need them -/// when monomorphizing, and they may not appear in the upvars. A -/// closure could capture no variables but still make use of some -/// in-scope type parameter with a bound (e.g., if our example above -/// had an extra `U: Default`, and the closure called `U::default()`). -/// -/// There is another reason. This design (implicitly) prohibits -/// closures from capturing themselves (except via a trait -/// object). This simplifies closure inference considerably, since it -/// means that when we infer the kind of a closure or its upvars, we -/// don't have to handle cycles where the decisions we make for -/// closure C wind up influencing the decisions we ought to make for -/// closure C (which would then require fixed point iteration to -/// handle). Plus it fixes an ICE. :P -/// -/// ## Generators -/// -/// Generators are handled similarly in `GeneratorSubsts`. The set of -/// type parameters is similar, but `CK` and `CS` are replaced by the -/// following type parameters: -/// -/// * `GS`: The generator's "resume type", which is the type of the -/// argument passed to `resume`, and the type of `yield` expressions -/// inside the generator. -/// * `GY`: The "yield type", which is the type of values passed to -/// `yield` inside the generator. -/// * `GR`: The "return type", which is the type of value returned upon -/// completion of the generator. -/// * `GW`: The "generator witness". -#[derive(Copy, Clone, Debug, TypeFoldable)] -pub struct ClosureSubsts<'tcx> { - /// Lifetime and type parameters from the enclosing function, - /// concatenated with the types of the upvars. - /// - /// These are separated out because codegen wants to pass them around - /// when monomorphizing. - pub substs: SubstsRef<'tcx>, -} - -/// Struct returned by `split()`. Note that these are subslices of the -/// parent slice and not canonical substs themselves. -struct SplitClosureSubsts<'tcx> { - closure_kind_ty: Ty<'tcx>, - closure_sig_ty: Ty<'tcx>, - upvar_kinds: &'tcx [GenericArg<'tcx>], -} - -impl<'tcx> ClosureSubsts<'tcx> { - /// Divides the closure substs into their respective - /// components. Single source of truth with respect to the - /// ordering. - fn split(self, def_id: DefId, tcx: TyCtxt<'_>) -> SplitClosureSubsts<'tcx> { - let generics = tcx.generics_of(def_id); - let parent_len = generics.parent_count; - SplitClosureSubsts { - closure_kind_ty: self.substs.type_at(parent_len), - closure_sig_ty: self.substs.type_at(parent_len + 1), - upvar_kinds: &self.substs[parent_len + 2..], - } - } - - #[inline] - pub fn upvar_tys( - self, - def_id: DefId, - tcx: TyCtxt<'_>, - ) -> impl Iterator<Item = Ty<'tcx>> + 'tcx { - let SplitClosureSubsts { upvar_kinds, .. } = self.split(def_id, tcx); - upvar_kinds.iter().map(|t| { - if let GenericArgKind::Type(ty) = t.unpack() { - ty - } else { - bug!("upvar should be type") - } - }) - } - - /// Returns the closure kind for this closure; may return a type - /// variable during inference. To get the closure kind during - /// inference, use `infcx.closure_kind(def_id, substs)`. - pub fn kind_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> { - self.split(def_id, tcx).closure_kind_ty - } - - /// Returns the type representing the closure signature for this - /// closure; may contain type variables during inference. To get - /// the closure signature during inference, use - /// `infcx.fn_sig(def_id)`. - pub fn sig_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> { - self.split(def_id, tcx).closure_sig_ty - } - - /// Returns the closure kind for this closure; only usable outside - /// of an inference context, because in that context we know that - /// there are no type variables. - /// - /// If you have an inference context, use `infcx.closure_kind()`. - pub fn kind(self, def_id: DefId, tcx: TyCtxt<'tcx>) -> ty::ClosureKind { - self.split(def_id, tcx).closure_kind_ty.to_opt_closure_kind().unwrap() - } - - /// Extracts the signature from the closure; only usable outside - /// of an inference context, because in that context we know that - /// there are no type variables. - /// - /// If you have an inference context, use `infcx.closure_sig()`. - pub fn sig(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { - let ty = self.sig_ty(def_id, tcx); - match ty.kind { - ty::FnPtr(sig) => sig, - _ => bug!("closure_sig_ty is not a fn-ptr: {:?}", ty.kind), - } - } -} - -/// Similar to `ClosureSubsts`; see the above documentation for more. -#[derive(Copy, Clone, Debug, TypeFoldable)] -pub struct GeneratorSubsts<'tcx> { - pub substs: SubstsRef<'tcx>, -} - -struct SplitGeneratorSubsts<'tcx> { - resume_ty: Ty<'tcx>, - yield_ty: Ty<'tcx>, - return_ty: Ty<'tcx>, - witness: Ty<'tcx>, - upvar_kinds: &'tcx [GenericArg<'tcx>], -} - -impl<'tcx> GeneratorSubsts<'tcx> { - fn split(self, def_id: DefId, tcx: TyCtxt<'_>) -> SplitGeneratorSubsts<'tcx> { - let generics = tcx.generics_of(def_id); - let parent_len = generics.parent_count; - SplitGeneratorSubsts { - resume_ty: self.substs.type_at(parent_len), - yield_ty: self.substs.type_at(parent_len + 1), - return_ty: self.substs.type_at(parent_len + 2), - witness: self.substs.type_at(parent_len + 3), - upvar_kinds: &self.substs[parent_len + 4..], - } - } - - /// This describes the types that can be contained in a generator. - /// It will be a type variable initially and unified in the last stages of typeck of a body. - /// It contains a tuple of all the types that could end up on a generator frame. - /// The state transformation MIR pass may only produce layouts which mention types - /// in this tuple. Upvars are not counted here. - pub fn witness(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> { - self.split(def_id, tcx).witness - } - - #[inline] - pub fn upvar_tys( - self, - def_id: DefId, - tcx: TyCtxt<'_>, - ) -> impl Iterator<Item = Ty<'tcx>> + 'tcx { - let SplitGeneratorSubsts { upvar_kinds, .. } = self.split(def_id, tcx); - upvar_kinds.iter().map(|t| { - if let GenericArgKind::Type(ty) = t.unpack() { - ty - } else { - bug!("upvar should be type") - } - }) - } - - /// Returns the type representing the resume type of the generator. - pub fn resume_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> { - self.split(def_id, tcx).resume_ty - } - - /// Returns the type representing the yield type of the generator. - pub fn yield_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> { - self.split(def_id, tcx).yield_ty - } - - /// Returns the type representing the return type of the generator. - pub fn return_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> { - self.split(def_id, tcx).return_ty - } - - /// Returns the "generator signature", which consists of its yield - /// and return types. - /// - /// N.B., some bits of the code prefers to see this wrapped in a - /// binder, but it never contains bound regions. Probably this - /// function should be removed. - pub fn poly_sig(self, def_id: DefId, tcx: TyCtxt<'_>) -> PolyGenSig<'tcx> { - ty::Binder::dummy(self.sig(def_id, tcx)) - } - - /// Returns the "generator signature", which consists of its resume, yield - /// and return types. - pub fn sig(self, def_id: DefId, tcx: TyCtxt<'_>) -> GenSig<'tcx> { - ty::GenSig { - resume_ty: self.resume_ty(def_id, tcx), - yield_ty: self.yield_ty(def_id, tcx), - return_ty: self.return_ty(def_id, tcx), - } - } -} - -impl<'tcx> GeneratorSubsts<'tcx> { - /// Generator has not been resumed yet. - pub const UNRESUMED: usize = 0; - /// Generator has returned or is completed. - pub const RETURNED: usize = 1; - /// Generator has been poisoned. - pub const POISONED: usize = 2; - - const UNRESUMED_NAME: &'static str = "Unresumed"; - const RETURNED_NAME: &'static str = "Returned"; - const POISONED_NAME: &'static str = "Panicked"; - - /// The valid variant indices of this generator. - #[inline] - pub fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range<VariantIdx> { - // FIXME requires optimized MIR - let num_variants = tcx.generator_layout(def_id).variant_fields.len(); - VariantIdx::new(0)..VariantIdx::new(num_variants) - } - - /// The discriminant for the given variant. Panics if the `variant_index` is - /// out of range. - #[inline] - pub fn discriminant_for_variant( - &self, - def_id: DefId, - tcx: TyCtxt<'tcx>, - variant_index: VariantIdx, - ) -> Discr<'tcx> { - // Generators don't support explicit discriminant values, so they are - // the same as the variant index. - assert!(self.variant_range(def_id, tcx).contains(&variant_index)); - Discr { val: variant_index.as_usize() as u128, ty: self.discr_ty(tcx) } - } - - /// The set of all discriminants for the generator, enumerated with their - /// variant indices. - #[inline] - pub fn discriminants( - self, - def_id: DefId, - tcx: TyCtxt<'tcx>, - ) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> + Captures<'tcx> { - self.variant_range(def_id, tcx).map(move |index| { - (index, Discr { val: index.as_usize() as u128, ty: self.discr_ty(tcx) }) - }) - } - - /// Calls `f` with a reference to the name of the enumerator for the given - /// variant `v`. - #[inline] - pub fn variant_name(self, v: VariantIdx) -> Cow<'static, str> { - match v.as_usize() { - Self::UNRESUMED => Cow::from(Self::UNRESUMED_NAME), - Self::RETURNED => Cow::from(Self::RETURNED_NAME), - Self::POISONED => Cow::from(Self::POISONED_NAME), - _ => Cow::from(format!("Suspend{}", v.as_usize() - 3)), - } - } - - /// The type of the state discriminant used in the generator type. - #[inline] - pub fn discr_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.types.u32 - } - - /// This returns the types of the MIR locals which had to be stored across suspension points. - /// It is calculated in rustc_mir::transform::generator::StateTransform. - /// All the types here must be in the tuple in GeneratorInterior. - /// - /// The locals are grouped by their variant number. Note that some locals may - /// be repeated in multiple variants. - #[inline] - pub fn state_tys( - self, - def_id: DefId, - tcx: TyCtxt<'tcx>, - ) -> impl Iterator<Item = impl Iterator<Item = Ty<'tcx>> + Captures<'tcx>> { - let layout = tcx.generator_layout(def_id); - layout.variant_fields.iter().map(move |variant| { - variant.iter().map(move |field| layout.field_tys[*field].subst(tcx, self.substs)) - }) - } - - /// This is the types of the fields of a generator which are not stored in a - /// variant. - #[inline] - pub fn prefix_tys(self, def_id: DefId, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = Ty<'tcx>> { - self.upvar_tys(def_id, tcx) - } -} - -#[derive(Debug, Copy, Clone)] -pub enum UpvarSubsts<'tcx> { - Closure(SubstsRef<'tcx>), - Generator(SubstsRef<'tcx>), -} - -impl<'tcx> UpvarSubsts<'tcx> { - #[inline] - pub fn upvar_tys( - self, - def_id: DefId, - tcx: TyCtxt<'tcx>, - ) -> impl Iterator<Item = Ty<'tcx>> + 'tcx { - let upvar_kinds = match self { - UpvarSubsts::Closure(substs) => substs.as_closure().split(def_id, tcx).upvar_kinds, - UpvarSubsts::Generator(substs) => substs.as_generator().split(def_id, tcx).upvar_kinds, - }; - upvar_kinds.iter().map(|t| { - if let GenericArgKind::Type(ty) = t.unpack() { - ty - } else { - bug!("upvar should be type") - } - }) - } -} - -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable)] -pub enum ExistentialPredicate<'tcx> { - /// E.g., `Iterator`. - Trait(ExistentialTraitRef<'tcx>), - /// E.g., `Iterator::Item = T`. - Projection(ExistentialProjection<'tcx>), - /// E.g., `Send`. - AutoTrait(DefId), -} - -impl<'tcx> ExistentialPredicate<'tcx> { - /// Compares via an ordering that will not change if modules are reordered or other changes are - /// made to the tree. In particular, this ordering is preserved across incremental compilations. - pub fn stable_cmp(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Ordering { - use self::ExistentialPredicate::*; - match (*self, *other) { - (Trait(_), Trait(_)) => Ordering::Equal, - (Projection(ref a), Projection(ref b)) => { - tcx.def_path_hash(a.item_def_id).cmp(&tcx.def_path_hash(b.item_def_id)) - } - (AutoTrait(ref a), AutoTrait(ref b)) => { - tcx.trait_def(*a).def_path_hash.cmp(&tcx.trait_def(*b).def_path_hash) - } - (Trait(_), _) => Ordering::Less, - (Projection(_), Trait(_)) => Ordering::Greater, - (Projection(_), _) => Ordering::Less, - (AutoTrait(_), _) => Ordering::Greater, - } - } -} - -impl<'tcx> Binder<ExistentialPredicate<'tcx>> { - pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { - use crate::ty::ToPredicate; - match *self.skip_binder() { - ExistentialPredicate::Trait(tr) => { - Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate() - } - ExistentialPredicate::Projection(p) => { - ty::Predicate::Projection(Binder(p.with_self_ty(tcx, self_ty))) - } - ExistentialPredicate::AutoTrait(did) => { - let trait_ref = - Binder(ty::TraitRef { def_id: did, substs: tcx.mk_substs_trait(self_ty, &[]) }); - trait_ref.without_const().to_predicate() - } - } - } -} - -impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx List<ExistentialPredicate<'tcx>> {} - -impl<'tcx> List<ExistentialPredicate<'tcx>> { - /// Returns the "principal `DefId`" of this set of existential predicates. - /// - /// A Rust trait object type consists (in addition to a lifetime bound) - /// of a set of trait bounds, which are separated into any number - /// of auto-trait bounds, and at most one non-auto-trait bound. The - /// non-auto-trait bound is called the "principal" of the trait - /// object. - /// - /// Only the principal can have methods or type parameters (because - /// auto traits can have neither of them). This is important, because - /// it means the auto traits can be treated as an unordered set (methods - /// would force an order for the vtable, while relating traits with - /// type parameters without knowing the order to relate them in is - /// a rather non-trivial task). - /// - /// For example, in the trait object `dyn fmt::Debug + Sync`, the - /// principal bound is `Some(fmt::Debug)`, while the auto-trait bounds - /// are the set `{Sync}`. - /// - /// It is also possible to have a "trivial" trait object that - /// consists only of auto traits, with no principal - for example, - /// `dyn Send + Sync`. In that case, the set of auto-trait bounds - /// is `{Send, Sync}`, while there is no principal. These trait objects - /// have a "trivial" vtable consisting of just the size, alignment, - /// and destructor. - pub fn principal(&self) -> Option<ExistentialTraitRef<'tcx>> { - match self[0] { - ExistentialPredicate::Trait(tr) => Some(tr), - _ => None, - } - } - - pub fn principal_def_id(&self) -> Option<DefId> { - self.principal().map(|trait_ref| trait_ref.def_id) - } - - #[inline] - pub fn projection_bounds<'a>( - &'a self, - ) -> impl Iterator<Item = ExistentialProjection<'tcx>> + 'a { - self.iter().filter_map(|predicate| match *predicate { - ExistentialPredicate::Projection(projection) => Some(projection), - _ => None, - }) - } - - #[inline] - pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + 'a { - self.iter().filter_map(|predicate| match *predicate { - ExistentialPredicate::AutoTrait(did) => Some(did), - _ => None, - }) - } -} - -impl<'tcx> Binder<&'tcx List<ExistentialPredicate<'tcx>>> { - pub fn principal(&self) -> Option<ty::Binder<ExistentialTraitRef<'tcx>>> { - self.skip_binder().principal().map(Binder::bind) - } - - pub fn principal_def_id(&self) -> Option<DefId> { - self.skip_binder().principal_def_id() - } - - #[inline] - pub fn projection_bounds<'a>( - &'a self, - ) -> impl Iterator<Item = PolyExistentialProjection<'tcx>> + 'a { - self.skip_binder().projection_bounds().map(Binder::bind) - } - - #[inline] - pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + 'a { - self.skip_binder().auto_traits() - } - - pub fn iter<'a>( - &'a self, - ) -> impl DoubleEndedIterator<Item = Binder<ExistentialPredicate<'tcx>>> + 'tcx { - self.skip_binder().iter().cloned().map(Binder::bind) - } -} - -/// A complete reference to a trait. These take numerous guises in syntax, -/// but perhaps the most recognizable form is in a where-clause: -/// -/// T: Foo<U> -/// -/// This would be represented by a trait-reference where the `DefId` is the -/// `DefId` for the trait `Foo` and the substs define `T` as parameter 0, -/// and `U` as parameter 1. -/// -/// Trait references also appear in object types like `Foo<U>`, but in -/// that case the `Self` parameter is absent from the substitutions. -/// -/// Note that a `TraitRef` introduces a level of region binding, to -/// account for higher-ranked trait bounds like `T: for<'a> Foo<&'a U>` -/// or higher-ranked object types. -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable)] -pub struct TraitRef<'tcx> { - pub def_id: DefId, - pub substs: SubstsRef<'tcx>, -} - -impl<'tcx> TraitRef<'tcx> { - pub fn new(def_id: DefId, substs: SubstsRef<'tcx>) -> TraitRef<'tcx> { - TraitRef { def_id, substs } - } - - /// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi` - /// are the parameters defined on trait. - pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> { - TraitRef { def_id, substs: InternalSubsts::identity_for_item(tcx, def_id) } - } - - #[inline] - pub fn self_ty(&self) -> Ty<'tcx> { - self.substs.type_at(0) - } - - pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a { - // Select only the "input types" from a trait-reference. For - // now this is all the types that appear in the - // trait-reference, but it should eventually exclude - // associated types. - self.substs.types() - } - - pub fn from_method( - tcx: TyCtxt<'tcx>, - trait_id: DefId, - substs: SubstsRef<'tcx>, - ) -> ty::TraitRef<'tcx> { - let defs = tcx.generics_of(trait_id); - - ty::TraitRef { def_id: trait_id, substs: tcx.intern_substs(&substs[..defs.params.len()]) } - } -} - -pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>; - -impl<'tcx> PolyTraitRef<'tcx> { - pub fn self_ty(&self) -> Ty<'tcx> { - self.skip_binder().self_ty() - } - - pub fn def_id(&self) -> DefId { - self.skip_binder().def_id - } - - pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> { - // Note that we preserve binding levels - Binder(ty::TraitPredicate { trait_ref: *self.skip_binder() }) - } -} - -/// An existential reference to a trait, where `Self` is erased. -/// For example, the trait object `Trait<'a, 'b, X, Y>` is: -/// -/// exists T. T: Trait<'a, 'b, X, Y> -/// -/// The substitutions don't include the erased `Self`, only trait -/// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable)] -pub struct ExistentialTraitRef<'tcx> { - pub def_id: DefId, - pub substs: SubstsRef<'tcx>, -} - -impl<'tcx> ExistentialTraitRef<'tcx> { - pub fn input_types<'b>(&'b self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'b { - // Select only the "input types" from a trait-reference. For - // now this is all the types that appear in the - // trait-reference, but it should eventually exclude - // associated types. - self.substs.types() - } - - pub fn erase_self_ty( - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - ) -> ty::ExistentialTraitRef<'tcx> { - // Assert there is a Self. - trait_ref.substs.type_at(0); - - ty::ExistentialTraitRef { - def_id: trait_ref.def_id, - substs: tcx.intern_substs(&trait_ref.substs[1..]), - } - } - - /// Object types don't have a self type specified. Therefore, when - /// we convert the principal trait-ref into a normal trait-ref, - /// you must give *some* self type. A common choice is `mk_err()` - /// or some placeholder type. - pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::TraitRef<'tcx> { - // otherwise the escaping vars would be captured by the binder - // debug_assert!(!self_ty.has_escaping_bound_vars()); - - ty::TraitRef { def_id: self.def_id, substs: tcx.mk_substs_trait(self_ty, self.substs) } - } -} - -pub type PolyExistentialTraitRef<'tcx> = Binder<ExistentialTraitRef<'tcx>>; - -impl<'tcx> PolyExistentialTraitRef<'tcx> { - pub fn def_id(&self) -> DefId { - self.skip_binder().def_id - } - - /// Object types don't have a self type specified. Therefore, when - /// we convert the principal trait-ref into a normal trait-ref, - /// you must give *some* self type. A common choice is `mk_err()` - /// or some placeholder type. - pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::PolyTraitRef<'tcx> { - self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty)) - } -} - -/// Binder is a binder for higher-ranked lifetimes or types. It is part of the -/// compiler's representation for things like `for<'a> Fn(&'a isize)` -/// (which would be represented by the type `PolyTraitRef == -/// Binder<TraitRef>`). Note that when we instantiate, -/// erase, or otherwise "discharge" these bound vars, we change the -/// type from `Binder<T>` to just `T` (see -/// e.g., `liberate_late_bound_regions`). -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct Binder<T>(T); - -impl<T> Binder<T> { - /// Wraps `value` in a binder, asserting that `value` does not - /// contain any bound vars that would be bound by the - /// binder. This is commonly used to 'inject' a value T into a - /// different binding level. - pub fn dummy<'tcx>(value: T) -> Binder<T> - where - T: TypeFoldable<'tcx>, - { - debug_assert!(!value.has_escaping_bound_vars()); - Binder(value) - } - - /// Wraps `value` in a binder, binding higher-ranked vars (if any). - pub fn bind(value: T) -> Binder<T> { - Binder(value) - } - - /// Skips the binder and returns the "bound" value. This is a - /// risky thing to do because it's easy to get confused about - /// De Bruijn indices and the like. It is usually better to - /// discharge the binder using `no_bound_vars` or - /// `replace_late_bound_regions` or something like - /// that. `skip_binder` is only valid when you are either - /// extracting data that has nothing to do with bound vars, you - /// are doing some sort of test that does not involve bound - /// regions, or you are being very careful about your depth - /// accounting. - /// - /// Some examples where `skip_binder` is reasonable: - /// - /// - extracting the `DefId` from a PolyTraitRef; - /// - comparing the self type of a PolyTraitRef to see if it is equal to - /// a type parameter `X`, since the type `X` does not reference any regions - pub fn skip_binder(&self) -> &T { - &self.0 - } - - pub fn as_ref(&self) -> Binder<&T> { - Binder(&self.0) - } - - pub fn map_bound_ref<F, U>(&self, f: F) -> Binder<U> - where - F: FnOnce(&T) -> U, - { - self.as_ref().map_bound(f) - } - - pub fn map_bound<F, U>(self, f: F) -> Binder<U> - where - F: FnOnce(T) -> U, - { - Binder(f(self.0)) - } - - /// Unwraps and returns the value within, but only if it contains - /// no bound vars at all. (In other words, if this binder -- - /// and indeed any enclosing binder -- doesn't bind anything at - /// all.) Otherwise, returns `None`. - /// - /// (One could imagine having a method that just unwraps a single - /// binder, but permits late-bound vars bound by enclosing - /// binders, but that would require adjusting the debruijn - /// indices, and given the shallow binding structure we often use, - /// would not be that useful.) - pub fn no_bound_vars<'tcx>(self) -> Option<T> - where - T: TypeFoldable<'tcx>, - { - if self.skip_binder().has_escaping_bound_vars() { - None - } else { - Some(self.skip_binder().clone()) - } - } - - /// Given two things that have the same binder level, - /// and an operation that wraps on their contents, executes the operation - /// and then wraps its result. - /// - /// `f` should consider bound regions at depth 1 to be free, and - /// anything it produces with bound regions at depth 1 will be - /// bound in the resulting return value. - pub fn fuse<U, F, R>(self, u: Binder<U>, f: F) -> Binder<R> - where - F: FnOnce(T, U) -> R, - { - Binder(f(self.0, u.0)) - } - - /// Splits the contents into two things that share the same binder - /// level as the original, returning two distinct binders. - /// - /// `f` should consider bound regions at depth 1 to be free, and - /// anything it produces with bound regions at depth 1 will be - /// bound in the resulting return values. - pub fn split<U, V, F>(self, f: F) -> (Binder<U>, Binder<V>) - where - F: FnOnce(T) -> (U, V), - { - let (u, v) = f(self.0); - (Binder(u), Binder(v)) - } -} - -/// Represents the projection of an associated type. In explicit UFCS -/// form this would be written `<T as Trait<..>>::N`. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable)] -pub struct ProjectionTy<'tcx> { - /// The parameters of the associated item. - pub substs: SubstsRef<'tcx>, - - /// The `DefId` of the `TraitItem` for the associated type `N`. - /// - /// Note that this is not the `DefId` of the `TraitRef` containing this - /// associated type, which is in `tcx.associated_item(item_def_id).container`. - pub item_def_id: DefId, -} - -impl<'tcx> ProjectionTy<'tcx> { - /// Construct a `ProjectionTy` by searching the trait from `trait_ref` for the - /// associated item named `item_name`. - pub fn from_ref_and_name( - tcx: TyCtxt<'_>, - trait_ref: ty::TraitRef<'tcx>, - item_name: Ident, - ) -> ProjectionTy<'tcx> { - let item_def_id = tcx - .associated_items(trait_ref.def_id) - .find_by_name_and_kind(tcx, item_name, ty::AssocKind::Type, trait_ref.def_id) - .unwrap() - .def_id; - - ProjectionTy { substs: trait_ref.substs, item_def_id } - } - - /// Extracts the underlying trait reference from this projection. - /// For example, if this is a projection of `<T as Iterator>::Item`, - /// then this function would return a `T: Iterator` trait reference. - pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { - let def_id = tcx.associated_item(self.item_def_id).container.id(); - ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) } - } - - pub fn self_ty(&self) -> Ty<'tcx> { - self.substs.type_at(0) - } -} - -#[derive(Clone, Debug, TypeFoldable)] -pub struct GenSig<'tcx> { - pub resume_ty: Ty<'tcx>, - pub yield_ty: Ty<'tcx>, - pub return_ty: Ty<'tcx>, -} - -pub type PolyGenSig<'tcx> = Binder<GenSig<'tcx>>; - -impl<'tcx> PolyGenSig<'tcx> { - pub fn resume_ty(&self) -> ty::Binder<Ty<'tcx>> { - self.map_bound_ref(|sig| sig.resume_ty) - } - pub fn yield_ty(&self) -> ty::Binder<Ty<'tcx>> { - self.map_bound_ref(|sig| sig.yield_ty) - } - pub fn return_ty(&self) -> ty::Binder<Ty<'tcx>> { - self.map_bound_ref(|sig| sig.return_ty) - } -} - -/// Signature of a function type, which we have arbitrarily -/// decided to use to refer to the input/output types. -/// -/// - `inputs`: is the list of arguments and their modes. -/// - `output`: is the return type. -/// - `c_variadic`: indicates whether this is a C-variadic function. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable)] -pub struct FnSig<'tcx> { - pub inputs_and_output: &'tcx List<Ty<'tcx>>, - pub c_variadic: bool, - pub unsafety: hir::Unsafety, - pub abi: abi::Abi, -} - -impl<'tcx> FnSig<'tcx> { - pub fn inputs(&self) -> &'tcx [Ty<'tcx>] { - &self.inputs_and_output[..self.inputs_and_output.len() - 1] - } - - pub fn output(&self) -> Ty<'tcx> { - self.inputs_and_output[self.inputs_and_output.len() - 1] - } - - // Creates a minimal `FnSig` to be used when encountering a `TyKind::Error` in a fallible - // method. - fn fake() -> FnSig<'tcx> { - FnSig { - inputs_and_output: List::empty(), - c_variadic: false, - unsafety: hir::Unsafety::Normal, - abi: abi::Abi::Rust, - } - } -} - -pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>; - -impl<'tcx> PolyFnSig<'tcx> { - #[inline] - pub fn inputs(&self) -> Binder<&'tcx [Ty<'tcx>]> { - self.map_bound_ref(|fn_sig| fn_sig.inputs()) - } - #[inline] - pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> { - self.map_bound_ref(|fn_sig| fn_sig.inputs()[index]) - } - pub fn inputs_and_output(&self) -> ty::Binder<&'tcx List<Ty<'tcx>>> { - self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output) - } - #[inline] - pub fn output(&self) -> ty::Binder<Ty<'tcx>> { - self.map_bound_ref(|fn_sig| fn_sig.output()) - } - pub fn c_variadic(&self) -> bool { - self.skip_binder().c_variadic - } - pub fn unsafety(&self) -> hir::Unsafety { - self.skip_binder().unsafety - } - pub fn abi(&self) -> abi::Abi { - self.skip_binder().abi - } -} - -pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<FnSig<'tcx>>>; - -#[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub struct ParamTy { - pub index: u32, - pub name: Symbol, -} - -impl<'tcx> ParamTy { - pub fn new(index: u32, name: Symbol) -> ParamTy { - ParamTy { index, name: name } - } - - pub fn for_self() -> ParamTy { - ParamTy::new(0, kw::SelfUpper) - } - - pub fn for_def(def: &ty::GenericParamDef) -> ParamTy { - ParamTy::new(def.index, def.name) - } - - pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.mk_ty_param(self.index, self.name) - } -} - -#[derive( - Copy, - Clone, - Hash, - RustcEncodable, - RustcDecodable, - Eq, - PartialEq, - Ord, - PartialOrd, - HashStable -)] -pub struct ParamConst { - pub index: u32, - pub name: Symbol, -} - -impl<'tcx> ParamConst { - pub fn new(index: u32, name: Symbol) -> ParamConst { - ParamConst { index, name } - } - - pub fn for_def(def: &ty::GenericParamDef) -> ParamConst { - ParamConst::new(def.index, def.name) - } - - pub fn to_const(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Const<'tcx> { - tcx.mk_const_param(self.index, self.name, ty) - } -} - -rustc_index::newtype_index! { - /// A [De Bruijn index][dbi] is a standard means of representing - /// regions (and perhaps later types) in a higher-ranked setting. In - /// particular, imagine a type like this: - /// - /// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) - /// ^ ^ | | | - /// | | | | | - /// | +------------+ 0 | | - /// | | | - /// +--------------------------------+ 1 | - /// | | - /// +------------------------------------------+ 0 - /// - /// In this type, there are two binders (the outer fn and the inner - /// fn). We need to be able to determine, for any given region, which - /// fn type it is bound by, the inner or the outer one. There are - /// various ways you can do this, but a De Bruijn index is one of the - /// more convenient and has some nice properties. The basic idea is to - /// count the number of binders, inside out. Some examples should help - /// clarify what I mean. - /// - /// Let's start with the reference type `&'b isize` that is the first - /// argument to the inner function. This region `'b` is assigned a De - /// Bruijn index of 0, meaning "the innermost binder" (in this case, a - /// fn). The region `'a` that appears in the second argument type (`&'a - /// isize`) would then be assigned a De Bruijn index of 1, meaning "the - /// second-innermost binder". (These indices are written on the arrays - /// in the diagram). - /// - /// What is interesting is that De Bruijn index attached to a particular - /// variable will vary depending on where it appears. For example, - /// the final type `&'a char` also refers to the region `'a` declared on - /// the outermost fn. But this time, this reference is not nested within - /// any other binders (i.e., it is not an argument to the inner fn, but - /// rather the outer one). Therefore, in this case, it is assigned a - /// De Bruijn index of 0, because the innermost binder in that location - /// is the outer fn. - /// - /// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index - #[derive(HashStable)] - pub struct DebruijnIndex { - DEBUG_FORMAT = "DebruijnIndex({})", - const INNERMOST = 0, - } -} - -pub type Region<'tcx> = &'tcx RegionKind; - -/// Representation of (lexical) regions. Note that the NLL checker -/// uses a distinct representation of regions. For this reason, it -/// internally replaces all the regions with inference variables -- -/// the index of the variable is then used to index into internal NLL -/// data structures. See `rustc_mir::borrow_check` module for more -/// information. -/// -/// ## The Region lattice within a given function -/// -/// In general, the (lexical, and hence deprecated) region lattice -/// looks like -/// -/// ``` -/// static ----------+-----...------+ (greatest) -/// | | | -/// early-bound and | | -/// free regions | | -/// | | | -/// scope regions | | -/// | | | -/// empty(root) placeholder(U1) | -/// | / | -/// | / placeholder(Un) -/// empty(U1) -- / -/// | / -/// ... / -/// | / -/// empty(Un) -------- (smallest) -/// ``` -/// -/// Early-bound/free regions are the named lifetimes in scope from the -/// function declaration. They have relationships to one another -/// determined based on the declared relationships from the -/// function. They all collectively outlive the scope regions. (See -/// `RegionRelations` type, and particularly -/// `crate::infer::outlives::free_region_map::FreeRegionMap`.) -/// -/// The scope regions are related to one another based on the AST -/// structure. (See `RegionRelations` type, and particularly the -/// `rustc::middle::region::ScopeTree`.) -/// -/// Note that inference variables and bound regions are not included -/// in this diagram. In the case of inference variables, they should -/// be inferred to some other region from the diagram. In the case of -/// bound regions, they are excluded because they don't make sense to -/// include -- the diagram indicates the relationship between free -/// regions. -/// -/// ## Inference variables -/// -/// During region inference, we sometimes create inference variables, -/// represented as `ReVar`. These will be inferred by the code in -/// `infer::lexical_region_resolve` to some free region from the -/// lattice above (the minimal region that meets the -/// constraints). -/// -/// During NLL checking, where regions are defined differently, we -/// also use `ReVar` -- in that case, the index is used to index into -/// the NLL region checker's data structures. The variable may in fact -/// represent either a free region or an inference variable, in that -/// case. -/// -/// ## Bound Regions -/// -/// These are regions that are stored behind a binder and must be substituted -/// with some concrete region before being used. There are two kind of -/// bound regions: early-bound, which are bound in an item's `Generics`, -/// and are substituted by a `InternalSubsts`, and late-bound, which are part of -/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are substituted by -/// the likes of `liberate_late_bound_regions`. The distinction exists -/// because higher-ranked lifetimes aren't supported in all places. See [1][2]. -/// -/// Unlike `Param`s, bound regions are not supposed to exist "in the wild" -/// outside their binder, e.g., in types passed to type inference, and -/// should first be substituted (by placeholder regions, free regions, -/// or region variables). -/// -/// ## Placeholder and Free Regions -/// -/// One often wants to work with bound regions without knowing their precise -/// identity. For example, when checking a function, the lifetime of a borrow -/// can end up being assigned to some region parameter. In these cases, -/// it must be ensured that bounds on the region can't be accidentally -/// assumed without being checked. -/// -/// To do this, we replace the bound regions with placeholder markers, -/// which don't satisfy any relation not explicitly provided. -/// -/// There are two kinds of placeholder regions in rustc: `ReFree` and -/// `RePlaceholder`. When checking an item's body, `ReFree` is supposed -/// to be used. These also support explicit bounds: both the internally-stored -/// *scope*, which the region is assumed to outlive, as well as other -/// relations stored in the `FreeRegionMap`. Note that these relations -/// aren't checked when you `make_subregion` (or `eq_types`), only by -/// `resolve_regions_and_report_errors`. -/// -/// When working with higher-ranked types, some region relations aren't -/// yet known, so you can't just call `resolve_regions_and_report_errors`. -/// `RePlaceholder` is designed for this purpose. In these contexts, -/// there's also the risk that some inference variable laying around will -/// get unified with your placeholder region: if you want to check whether -/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a` -/// with a placeholder region `'%a`, the variable `'_` would just be -/// instantiated to the placeholder region `'%a`, which is wrong because -/// the inference variable is supposed to satisfy the relation -/// *for every value of the placeholder region*. To ensure that doesn't -/// happen, you can use `leak_check`. This is more clearly explained -/// by the [rustc guide]. -/// -/// [1]: http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ -/// [2]: http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ -/// [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/hrtb.html -#[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable, PartialOrd, Ord)] -pub enum RegionKind { - /// Region bound in a type or fn declaration which will be - /// substituted 'early' -- that is, at the same time when type - /// parameters are substituted. - ReEarlyBound(EarlyBoundRegion), - - /// Region bound in a function scope, which will be substituted when the - /// function is called. - ReLateBound(DebruijnIndex, BoundRegion), - - /// When checking a function body, the types of all arguments and so forth - /// that refer to bound region parameters are modified to refer to free - /// region parameters. - ReFree(FreeRegion), - - /// A concrete region naming some statically determined scope - /// (e.g., an expression or sequence of statements) within the - /// current function. - ReScope(region::Scope), - - /// Static data that has an "infinite" lifetime. Top in the region lattice. - ReStatic, - - /// A region variable. Should not exist after typeck. - ReVar(RegionVid), - - /// A placeholder region -- basically, the higher-ranked version of `ReFree`. - /// Should not exist after typeck. - RePlaceholder(ty::PlaceholderRegion), - - /// Empty lifetime is for data that is never accessed. We tag the - /// empty lifetime with a universe -- the idea is that we don't - /// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable. - /// Therefore, the `'empty` in a universe `U` is less than all - /// regions visible from `U`, but not less than regions not visible - /// from `U`. - ReEmpty(ty::UniverseIndex), - - /// Erased region, used by trait selection, in MIR and during codegen. - ReErased, - - /// These are regions bound in the "defining type" for a - /// closure. They are used ONLY as part of the - /// `ClosureRegionRequirements` that are produced by MIR borrowck. - /// See `ClosureRegionRequirements` for more details. - ReClosureBound(RegionVid), -} - -impl<'tcx> rustc_serialize::UseSpecializedDecodable for Region<'tcx> {} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, PartialOrd, Ord)] -pub struct EarlyBoundRegion { - pub def_id: DefId, - pub index: u32, - pub name: Symbol, -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -pub struct TyVid { - pub index: u32, -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -pub struct ConstVid<'tcx> { - pub index: u32, - pub phantom: PhantomData<&'tcx ()>, -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -pub struct IntVid { - pub index: u32, -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -pub struct FloatVid { - pub index: u32, -} - -rustc_index::newtype_index! { - pub struct RegionVid { - DEBUG_FORMAT = custom, - } -} - -impl Atom for RegionVid { - fn index(self) -> usize { - Idx::index(self) - } -} - -#[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub enum InferTy { - TyVar(TyVid), - IntVar(IntVid), - FloatVar(FloatVid), - - /// A `FreshTy` is one that is generated as a replacement for an - /// unbound type variable. This is convenient for caching etc. See - /// `infer::freshen` for more details. - FreshTy(u32), - FreshIntTy(u32), - FreshFloatTy(u32), -} - -rustc_index::newtype_index! { - pub struct BoundVar { .. } -} - -#[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Debug, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub struct BoundTy { - pub var: BoundVar, - pub kind: BoundTyKind, -} - -#[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Debug, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub enum BoundTyKind { - Anon, - Param(Symbol), -} - -impl From<BoundVar> for BoundTy { - fn from(var: BoundVar) -> Self { - BoundTy { var, kind: BoundTyKind::Anon } - } -} - -/// A `ProjectionPredicate` for an `ExistentialTraitRef`. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable)] -pub struct ExistentialProjection<'tcx> { - pub item_def_id: DefId, - pub substs: SubstsRef<'tcx>, - pub ty: Ty<'tcx>, -} - -pub type PolyExistentialProjection<'tcx> = Binder<ExistentialProjection<'tcx>>; - -impl<'tcx> ExistentialProjection<'tcx> { - /// Extracts the underlying existential trait reference from this projection. - /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`, - /// then this function would return a `exists T. T: Iterator` existential trait - /// reference. - pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::ExistentialTraitRef<'tcx> { - let def_id = tcx.associated_item(self.item_def_id).container.id(); - ty::ExistentialTraitRef { def_id, substs: self.substs } - } - - pub fn with_self_ty( - &self, - tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, - ) -> ty::ProjectionPredicate<'tcx> { - // otherwise the escaping regions would be captured by the binders - debug_assert!(!self_ty.has_escaping_bound_vars()); - - ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - item_def_id: self.item_def_id, - substs: tcx.mk_substs_trait(self_ty, self.substs), - }, - ty: self.ty, - } - } -} - -impl<'tcx> PolyExistentialProjection<'tcx> { - pub fn with_self_ty( - &self, - tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, - ) -> ty::PolyProjectionPredicate<'tcx> { - self.map_bound(|p| p.with_self_ty(tcx, self_ty)) - } - - pub fn item_def_id(&self) -> DefId { - return self.skip_binder().item_def_id; - } -} - -impl DebruijnIndex { - /// Returns the resulting index when this value is moved into - /// `amount` number of new binders. So, e.g., if you had - /// - /// for<'a> fn(&'a x) - /// - /// and you wanted to change it to - /// - /// for<'a> fn(for<'b> fn(&'a x)) - /// - /// you would need to shift the index for `'a` into a new binder. - #[must_use] - pub fn shifted_in(self, amount: u32) -> DebruijnIndex { - DebruijnIndex::from_u32(self.as_u32() + amount) - } - - /// Update this index in place by shifting it "in" through - /// `amount` number of binders. - pub fn shift_in(&mut self, amount: u32) { - *self = self.shifted_in(amount); - } - - /// Returns the resulting index when this value is moved out from - /// `amount` number of new binders. - #[must_use] - pub fn shifted_out(self, amount: u32) -> DebruijnIndex { - DebruijnIndex::from_u32(self.as_u32() - amount) - } - - /// Update in place by shifting out from `amount` binders. - pub fn shift_out(&mut self, amount: u32) { - *self = self.shifted_out(amount); - } - - /// Adjusts any De Bruijn indices so as to make `to_binder` the - /// innermost binder. That is, if we have something bound at `to_binder`, - /// it will now be bound at INNERMOST. This is an appropriate thing to do - /// when moving a region out from inside binders: - /// - /// ``` - /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _) - /// // Binder: D3 D2 D1 ^^ - /// ``` - /// - /// Here, the region `'a` would have the De Bruijn index D3, - /// because it is the bound 3 binders out. However, if we wanted - /// to refer to that region `'a` in the second argument (the `_`), - /// those two binders would not be in scope. In that case, we - /// might invoke `shift_out_to_binder(D3)`. This would adjust the - /// De Bruijn index of `'a` to D1 (the innermost binder). - /// - /// If we invoke `shift_out_to_binder` and the region is in fact - /// bound by one of the binders we are shifting out of, that is an - /// error (and should fail an assertion failure). - pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self { - self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32()) - } -} - -/// Region utilities -impl RegionKind { - /// Is this region named by the user? - pub fn has_name(&self) -> bool { - match *self { - RegionKind::ReEarlyBound(ebr) => ebr.has_name(), - RegionKind::ReLateBound(_, br) => br.is_named(), - RegionKind::ReFree(fr) => fr.bound_region.is_named(), - RegionKind::ReScope(..) => false, - RegionKind::ReStatic => true, - RegionKind::ReVar(..) => false, - RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(), - RegionKind::ReEmpty(_) => false, - RegionKind::ReErased => false, - RegionKind::ReClosureBound(..) => false, - } - } - - pub fn is_late_bound(&self) -> bool { - match *self { - ty::ReLateBound(..) => true, - _ => false, - } - } - - pub fn is_placeholder(&self) -> bool { - match *self { - ty::RePlaceholder(..) => true, - _ => false, - } - } - - pub fn bound_at_or_above_binder(&self, index: DebruijnIndex) -> bool { - match *self { - ty::ReLateBound(debruijn, _) => debruijn >= index, - _ => false, - } - } - - /// Adjusts any De Bruijn indices so as to make `to_binder` the - /// innermost binder. That is, if we have something bound at `to_binder`, - /// it will now be bound at INNERMOST. This is an appropriate thing to do - /// when moving a region out from inside binders: - /// - /// ``` - /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _) - /// // Binder: D3 D2 D1 ^^ - /// ``` - /// - /// Here, the region `'a` would have the De Bruijn index D3, - /// because it is the bound 3 binders out. However, if we wanted - /// to refer to that region `'a` in the second argument (the `_`), - /// those two binders would not be in scope. In that case, we - /// might invoke `shift_out_to_binder(D3)`. This would adjust the - /// De Bruijn index of `'a` to D1 (the innermost binder). - /// - /// If we invoke `shift_out_to_binder` and the region is in fact - /// bound by one of the binders we are shifting out of, that is an - /// error (and should fail an assertion failure). - pub fn shifted_out_to_binder(&self, to_binder: ty::DebruijnIndex) -> RegionKind { - match *self { - ty::ReLateBound(debruijn, r) => { - ty::ReLateBound(debruijn.shifted_out_to_binder(to_binder), r) - } - r => r, - } - } - - pub fn keep_in_local_tcx(&self) -> bool { - if let ty::ReVar(..) = self { true } else { false } - } - - pub fn type_flags(&self) -> TypeFlags { - let mut flags = TypeFlags::empty(); - - if self.keep_in_local_tcx() { - flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX; - } - - match *self { - ty::ReVar(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_RE_INFER; - } - ty::RePlaceholder(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; - } - ty::ReLateBound(..) => { - flags = flags | TypeFlags::HAS_RE_LATE_BOUND; - } - ty::ReEarlyBound(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_RE_EARLY_BOUND; - } - ty::ReEmpty(_) | ty::ReStatic | ty::ReFree { .. } | ty::ReScope { .. } => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - } - ty::ReErased => { - flags = flags | TypeFlags::HAS_RE_ERASED; - } - ty::ReClosureBound(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - } - } - - match *self { - ty::ReStatic | ty::ReEmpty(_) | ty::ReErased | ty::ReLateBound(..) => (), - _ => flags = flags | TypeFlags::HAS_FREE_LOCAL_NAMES, - } - - debug!("type_flags({:?}) = {:?}", self, flags); - - flags - } - - /// Given an early-bound or free region, returns the `DefId` where it was bound. - /// For example, consider the regions in this snippet of code: - /// - /// ``` - /// impl<'a> Foo { - /// ^^ -- early bound, declared on an impl - /// - /// fn bar<'b, 'c>(x: &self, y: &'b u32, z: &'c u64) where 'static: 'c - /// ^^ ^^ ^ anonymous, late-bound - /// | early-bound, appears in where-clauses - /// late-bound, appears only in fn args - /// {..} - /// } - /// ``` - /// - /// Here, `free_region_binding_scope('a)` would return the `DefId` - /// of the impl, and for all the other highlighted regions, it - /// would return the `DefId` of the function. In other cases (not shown), this - /// function might return the `DefId` of a closure. - pub fn free_region_binding_scope(&self, tcx: TyCtxt<'_>) -> DefId { - match self { - ty::ReEarlyBound(br) => tcx.parent(br.def_id).unwrap(), - ty::ReFree(fr) => fr.scope, - _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self), - } - } -} - -/// Type utilities -impl<'tcx> TyS<'tcx> { - #[inline] - pub fn is_unit(&self) -> bool { - match self.kind { - Tuple(ref tys) => tys.is_empty(), - _ => false, - } - } - - #[inline] - pub fn is_never(&self) -> bool { - match self.kind { - Never => true, - _ => false, - } - } - - /// Checks whether a type is definitely uninhabited. This is - /// conservative: for some types that are uninhabited we return `false`, - /// but we only return `true` for types that are definitely uninhabited. - /// `ty.conservative_is_privately_uninhabited` implies that any value of type `ty` - /// will be `Abi::Uninhabited`. (Note that uninhabited types may have nonzero - /// size, to account for partial initialisation. See #49298 for details.) - pub fn conservative_is_privately_uninhabited(&self, tcx: TyCtxt<'tcx>) -> bool { - // FIXME(varkor): we can make this less conversative by substituting concrete - // type arguments. - match self.kind { - ty::Never => true, - ty::Adt(def, _) if def.is_union() => { - // For now, `union`s are never considered uninhabited. - false - } - ty::Adt(def, _) => { - // Any ADT is uninhabited if either: - // (a) It has no variants (i.e. an empty `enum`); - // (b) Each of its variants (a single one in the case of a `struct`) has at least - // one uninhabited field. - def.variants.iter().all(|var| { - var.fields.iter().any(|field| { - tcx.type_of(field.did).conservative_is_privately_uninhabited(tcx) - }) - }) - } - ty::Tuple(..) => { - self.tuple_fields().any(|ty| ty.conservative_is_privately_uninhabited(tcx)) - } - ty::Array(ty, len) => { - match len.try_eval_usize(tcx, ParamEnv::empty()) { - // If the array is definitely non-empty, it's uninhabited if - // the type of its elements is uninhabited. - Some(n) if n != 0 => ty.conservative_is_privately_uninhabited(tcx), - _ => false, - } - } - ty::Ref(..) => { - // References to uninitialised memory is valid for any type, including - // uninhabited types, in unsafe code, so we treat all references as - // inhabited. - false - } - _ => false, - } - } - - #[inline] - pub fn is_primitive(&self) -> bool { - match self.kind { - Bool | Char | Int(_) | Uint(_) | Float(_) => true, - _ => false, - } - } - - #[inline] - pub fn is_ty_var(&self) -> bool { - match self.kind { - Infer(TyVar(_)) => true, - _ => false, - } - } - - #[inline] - pub fn is_ty_infer(&self) -> bool { - match self.kind { - Infer(_) => true, - _ => false, - } - } - - #[inline] - pub fn is_phantom_data(&self) -> bool { - if let Adt(def, _) = self.kind { def.is_phantom_data() } else { false } - } - - #[inline] - pub fn is_bool(&self) -> bool { - self.kind == Bool - } - - /// Returns `true` if this type is a `str`. - #[inline] - pub fn is_str(&self) -> bool { - self.kind == Str - } - - #[inline] - pub fn is_param(&self, index: u32) -> bool { - match self.kind { - ty::Param(ref data) => data.index == index, - _ => false, - } - } - - #[inline] - pub fn is_slice(&self) -> bool { - match self.kind { - RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.kind { - Slice(_) | Str => true, - _ => false, - }, - _ => false, - } - } - - #[inline] - pub fn is_simd(&self) -> bool { - match self.kind { - Adt(def, _) => def.repr.simd(), - _ => false, - } - } - - pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.kind { - Array(ty, _) | Slice(ty) => ty, - Str => tcx.mk_mach_uint(ast::UintTy::U8), - _ => bug!("`sequence_element_type` called on non-sequence value: {}", self), - } - } - - pub fn simd_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.kind { - Adt(def, substs) => def.non_enum_variant().fields[0].ty(tcx, substs), - _ => bug!("`simd_type` called on invalid type"), - } - } - - pub fn simd_size(&self, _tcx: TyCtxt<'tcx>) -> u64 { - // Parameter currently unused, but probably needed in the future to - // allow `#[repr(simd)] struct Simd<T, const N: usize>([T; N]);`. - match self.kind { - Adt(def, _) => def.non_enum_variant().fields.len() as u64, - _ => bug!("`simd_size` called on invalid type"), - } - } - - pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { - match self.kind { - Adt(def, substs) => { - let variant = def.non_enum_variant(); - (variant.fields.len() as u64, variant.fields[0].ty(tcx, substs)) - } - _ => bug!("`simd_size_and_type` called on invalid type"), - } - } - - #[inline] - pub fn is_region_ptr(&self) -> bool { - match self.kind { - Ref(..) => true, - _ => false, - } - } - - #[inline] - pub fn is_mutable_ptr(&self) -> bool { - match self.kind { - RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. }) - | Ref(_, _, hir::Mutability::Mut) => true, - _ => false, - } - } - - #[inline] - pub fn is_unsafe_ptr(&self) -> bool { - match self.kind { - RawPtr(_) => return true, - _ => return false, - } - } - - /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer). - #[inline] - pub fn is_any_ptr(&self) -> bool { - self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr() - } - - /// Returns `true` if this type is an `Arc<T>`. - #[inline] - pub fn is_arc(&self) -> bool { - match self.kind { - Adt(def, _) => def.is_arc(), - _ => false, - } - } - - /// Returns `true` if this type is an `Rc<T>`. - #[inline] - pub fn is_rc(&self) -> bool { - match self.kind { - Adt(def, _) => def.is_rc(), - _ => false, - } - } - - #[inline] - pub fn is_box(&self) -> bool { - match self.kind { - Adt(def, _) => def.is_box(), - _ => false, - } - } - - /// Panics if called on any type other than `Box<T>`. - pub fn boxed_ty(&self) -> Ty<'tcx> { - match self.kind { - Adt(def, substs) if def.is_box() => substs.type_at(0), - _ => bug!("`boxed_ty` is called on non-box type {:?}", self), - } - } - - /// A scalar type is one that denotes an atomic datum, with no sub-components. - /// (A RawPtr is scalar because it represents a non-managed pointer, so its - /// contents are abstract to rustc.) - #[inline] - pub fn is_scalar(&self) -> bool { - match self.kind { - Bool | Char | Int(_) | Float(_) | Uint(_) | Infer(IntVar(_)) | Infer(FloatVar(_)) - | FnDef(..) | FnPtr(_) | RawPtr(_) => true, - _ => false, - } - } - - /// Returns `true` if this type is a floating point type. - #[inline] - pub fn is_floating_point(&self) -> bool { - match self.kind { - Float(_) | Infer(FloatVar(_)) => true, - _ => false, - } - } - - #[inline] - pub fn is_trait(&self) -> bool { - match self.kind { - Dynamic(..) => true, - _ => false, - } - } - - #[inline] - pub fn is_enum(&self) -> bool { - match self.kind { - Adt(adt_def, _) => adt_def.is_enum(), - _ => false, - } - } - - #[inline] - pub fn is_closure(&self) -> bool { - match self.kind { - Closure(..) => true, - _ => false, - } - } - - #[inline] - pub fn is_generator(&self) -> bool { - match self.kind { - Generator(..) => true, - _ => false, - } - } - - #[inline] - pub fn is_integral(&self) -> bool { - match self.kind { - Infer(IntVar(_)) | Int(_) | Uint(_) => true, - _ => false, - } - } - - #[inline] - pub fn is_fresh_ty(&self) -> bool { - match self.kind { - Infer(FreshTy(_)) => true, - _ => false, - } - } - - #[inline] - pub fn is_fresh(&self) -> bool { - match self.kind { - Infer(FreshTy(_)) => true, - Infer(FreshIntTy(_)) => true, - Infer(FreshFloatTy(_)) => true, - _ => false, - } - } - - #[inline] - pub fn is_char(&self) -> bool { - match self.kind { - Char => true, - _ => false, - } - } - - #[inline] - pub fn is_numeric(&self) -> bool { - self.is_integral() || self.is_floating_point() - } - - #[inline] - pub fn is_signed(&self) -> bool { - match self.kind { - Int(_) => true, - _ => false, - } - } - - #[inline] - pub fn is_ptr_sized_integral(&self) -> bool { - match self.kind { - Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => true, - _ => false, - } - } - - #[inline] - pub fn is_machine(&self) -> bool { - match self.kind { - Int(..) | Uint(..) | Float(..) => true, - _ => false, - } - } - - #[inline] - pub fn has_concrete_skeleton(&self) -> bool { - match self.kind { - Param(_) | Infer(_) | Error => false, - _ => true, - } - } - - /// Returns the type and mutability of `*ty`. - /// - /// The parameter `explicit` indicates if this is an *explicit* dereference. - /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. - pub fn builtin_deref(&self, explicit: bool) -> Option<TypeAndMut<'tcx>> { - match self.kind { - Adt(def, _) if def.is_box() => { - Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not }) - } - Ref(_, ty, mutbl) => Some(TypeAndMut { ty, mutbl }), - RawPtr(mt) if explicit => Some(mt), - _ => None, - } - } - - /// Returns the type of `ty[i]`. - pub fn builtin_index(&self) -> Option<Ty<'tcx>> { - match self.kind { - Array(ty, _) | Slice(ty) => Some(ty), - _ => None, - } - } - - pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { - match self.kind { - FnDef(def_id, substs) => tcx.fn_sig(def_id).subst(tcx, substs), - FnPtr(f) => f, - Error => { - // ignore errors (#54954) - ty::Binder::dummy(FnSig::fake()) - } - Closure(..) => { - bug!("to get the signature of a closure, use `closure_sig()` not `fn_sig()`",) - } - _ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self), - } - } - - #[inline] - pub fn is_fn(&self) -> bool { - match self.kind { - FnDef(..) | FnPtr(_) => true, - _ => false, - } - } - - #[inline] - pub fn is_fn_ptr(&self) -> bool { - match self.kind { - FnPtr(_) => true, - _ => false, - } - } - - #[inline] - pub fn is_impl_trait(&self) -> bool { - match self.kind { - Opaque(..) => true, - _ => false, - } - } - - #[inline] - pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> { - match self.kind { - Adt(adt, _) => Some(adt), - _ => None, - } - } - - /// Iterates over tuple fields. - /// Panics when called on anything but a tuple. - pub fn tuple_fields(&self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> { - match self.kind { - Tuple(substs) => substs.iter().map(|field| field.expect_ty()), - _ => bug!("tuple_fields called on non-tuple"), - } - } - - /// If the type contains variants, returns the valid range of variant indices. - // - // FIXME: This requires the optimized MIR in the case of generators. - #[inline] - pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> { - match self.kind { - TyKind::Adt(adt, _) => Some(adt.variant_range()), - TyKind::Generator(def_id, substs, _) => { - Some(substs.as_generator().variant_range(def_id, tcx)) - } - _ => None, - } - } - - /// If the type contains variants, returns the variant for `variant_index`. - /// Panics if `variant_index` is out of range. - // - // FIXME: This requires the optimized MIR in the case of generators. - #[inline] - pub fn discriminant_for_variant( - &self, - tcx: TyCtxt<'tcx>, - variant_index: VariantIdx, - ) -> Option<Discr<'tcx>> { - match self.kind { - TyKind::Adt(adt, _) => Some(adt.discriminant_for_variant(tcx, variant_index)), - TyKind::Generator(def_id, substs, _) => { - Some(substs.as_generator().discriminant_for_variant(def_id, tcx, variant_index)) - } - _ => None, - } - } - - /// Pushes onto `out` the regions directly referenced from this type (but not - /// types reachable from this type via `walk_tys`). This ignores late-bound - /// regions binders. - pub fn push_regions(&self, out: &mut SmallVec<[ty::Region<'tcx>; 4]>) { - match self.kind { - Ref(region, _, _) => { - out.push(region); - } - Dynamic(ref obj, region) => { - out.push(region); - if let Some(principal) = obj.principal() { - out.extend(principal.skip_binder().substs.regions()); - } - } - Adt(_, substs) | Opaque(_, substs) => out.extend(substs.regions()), - Closure(_, ref substs) | Generator(_, ref substs, _) => out.extend(substs.regions()), - Projection(ref data) | UnnormalizedProjection(ref data) => { - out.extend(data.substs.regions()) - } - FnDef(..) | FnPtr(_) | GeneratorWitness(..) | Bool | Char | Int(_) | Uint(_) - | Float(_) | Str | Array(..) | Slice(_) | RawPtr(_) | Never | Tuple(..) - | Foreign(..) | Param(_) | Bound(..) | Placeholder(..) | Infer(_) | Error => {} - } - } - - /// When we create a closure, we record its kind (i.e., what trait - /// it implements) into its `ClosureSubsts` using a type - /// parameter. This is kind of a phantom type, except that the - /// most convenient thing for us to are the integral types. This - /// function converts such a special type into the closure - /// kind. To go the other way, use - /// `tcx.closure_kind_ty(closure_kind)`. - /// - /// Note that during type checking, we use an inference variable - /// to represent the closure kind, because it has not yet been - /// inferred. Once upvar inference (in `src/librustc_typeck/check/upvar.rs`) - /// is complete, that type variable will be unified. - pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> { - match self.kind { - Int(int_ty) => match int_ty { - ast::IntTy::I8 => Some(ty::ClosureKind::Fn), - ast::IntTy::I16 => Some(ty::ClosureKind::FnMut), - ast::IntTy::I32 => Some(ty::ClosureKind::FnOnce), - _ => bug!("cannot convert type `{:?}` to a closure kind", self), - }, - - // "Bound" types appear in canonical queries when the - // closure type is not yet known - Bound(..) | Infer(_) => None, - - Error => Some(ty::ClosureKind::Fn), - - _ => bug!("cannot convert type `{:?}` to a closure kind", self), - } - } - - /// Fast path helper for testing if a type is `Sized`. - /// - /// Returning true means the type is known to be sized. Returning - /// `false` means nothing -- could be sized, might not be. - pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool { - match self.kind { - ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::RawPtr(..) - | ty::Char - | ty::Ref(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::Array(..) - | ty::Closure(..) - | ty::Never - | ty::Error => true, - - ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false, - - ty::Tuple(tys) => tys.iter().all(|ty| ty.expect_ty().is_trivially_sized(tcx)), - - ty::Adt(def, _substs) => def.sized_constraint(tcx).is_empty(), - - ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => false, - - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - - ty::Infer(ty::TyVar(_)) => false, - - ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => { - bug!("`is_trivially_sized` applied to unexpected type: {:?}", self) - } - } - } -} - -/// Typed constant value. -#[derive( - Copy, - Clone, - Debug, - Hash, - RustcEncodable, - RustcDecodable, - Eq, - PartialEq, - Ord, - PartialOrd, - HashStable -)] -pub struct Const<'tcx> { - pub ty: Ty<'tcx>, - - pub val: ConstKind<'tcx>, -} - -#[cfg(target_arch = "x86_64")] -static_assert_size!(Const<'_>, 48); - -impl<'tcx> Const<'tcx> { - #[inline] - pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> &'tcx Self { - tcx.mk_const(Self { val: ConstKind::Value(val), ty }) - } - - #[inline] - pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> &'tcx Self { - Self::from_value(tcx, ConstValue::Scalar(val), ty) - } - - #[inline] - pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx Self { - let size = tcx - .layout_of(ty) - .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e)) - .size; - Self::from_scalar(tcx, Scalar::from_uint(bits, size), ty.value) - } - - #[inline] - pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Self { - Self::from_scalar(tcx, Scalar::zst(), ty) - } - - #[inline] - pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> &'tcx Self { - Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool)) - } - - #[inline] - pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> &'tcx Self { - Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize)) - } - - #[inline] - pub fn try_eval_bits( - &self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ty: Ty<'tcx>, - ) -> Option<u128> { - assert_eq!(self.ty, ty); - let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size; - // if `ty` does not depend on generic parameters, use an empty param_env - self.eval(tcx, param_env).val.try_to_bits(size) - } - - #[inline] - pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> { - let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs, promoted| { - let param_env_and_substs = param_env.with_reveal_all().and(substs); - - // Avoid querying `tcx.const_eval(...)` with any e.g. inference vars. - if param_env_and_substs.has_local_value() { - return None; - } - - let (param_env, substs) = param_env_and_substs.into_parts(); - - // try to resolve e.g. associated constants to their definition on an impl, and then - // evaluate the const. - tcx.const_eval_resolve(param_env, did, substs, promoted, None) - .ok() - .map(|val| Const::from_value(tcx, val, self.ty)) - }; - - match self.val { - ConstKind::Unevaluated(did, substs, promoted) => { - // HACK(eddyb) when substs contain e.g. inference variables, - // attempt using identity substs instead, that will succeed - // when the expression doesn't depend on any parameters. - // FIXME(eddyb) make `const_eval` a canonical query instead, - // that would properly handle inference variables in `substs`. - if substs.has_local_value() { - let identity_substs = InternalSubsts::identity_for_item(tcx, did); - // The `ParamEnv` needs to match the `identity_substs`. - let identity_param_env = tcx.param_env(did); - match try_const_eval(did, identity_param_env, identity_substs, promoted) { - Some(ct) => ct.subst(tcx, substs), - None => self, - } - } else { - try_const_eval(did, param_env, substs, promoted).unwrap_or(self) - } - } - _ => self, - } - } - - #[inline] - pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> { - self.try_eval_bits(tcx, param_env, tcx.types.bool).and_then(|v| match v { - 0 => Some(false), - 1 => Some(true), - _ => None, - }) - } - - #[inline] - pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> { - self.try_eval_bits(tcx, param_env, tcx.types.usize).map(|v| v as u64) - } - - #[inline] - pub fn eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 { - self.try_eval_bits(tcx, param_env, ty) - .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self)) - } - - #[inline] - pub fn eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 { - self.eval_bits(tcx, param_env, tcx.types.usize) as u64 - } -} - -impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {} - -/// Represents a constant in Rust. -#[derive( - Copy, - Clone, - Debug, - Eq, - PartialEq, - PartialOrd, - Ord, - RustcEncodable, - RustcDecodable, - Hash, - HashStable -)] -pub enum ConstKind<'tcx> { - /// A const generic parameter. - Param(ParamConst), - - /// Infer the value of the const. - Infer(InferConst<'tcx>), - - /// Bound const variable, used only when preparing a trait query. - Bound(DebruijnIndex, BoundVar), - - /// A placeholder const - universally quantified higher-ranked const. - Placeholder(ty::PlaceholderConst), - - /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other - /// variants when the code is monomorphic enough for that. - Unevaluated(DefId, SubstsRef<'tcx>, Option<Promoted>), - - /// Used to hold computed value. - Value(ConstValue<'tcx>), -} - -#[cfg(target_arch = "x86_64")] -static_assert_size!(ConstKind<'_>, 40); - -impl<'tcx> ConstKind<'tcx> { - #[inline] - pub fn try_to_scalar(&self) -> Option<Scalar> { - if let ConstKind::Value(val) = self { val.try_to_scalar() } else { None } - } - - #[inline] - pub fn try_to_bits(&self, size: ty::layout::Size) -> Option<u128> { - self.try_to_scalar()?.to_bits(size).ok() - } -} - -/// An inference variable for a const, for use in const generics. -#[derive( - Copy, - Clone, - Debug, - Eq, - PartialEq, - PartialOrd, - Ord, - RustcEncodable, - RustcDecodable, - Hash, - HashStable -)] -pub enum InferConst<'tcx> { - /// Infer the value of the const. - Var(ConstVid<'tcx>), - /// A fresh const variable. See `infer::freshen` for more details. - Fresh(u32), -} diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs deleted file mode 100644 index a0055812835..00000000000 --- a/src/librustc/ty/subst.rs +++ /dev/null @@ -1,724 +0,0 @@ -// Type substitutions. - -use crate::infer::canonical::Canonical; -use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use crate::ty::sty::{ClosureSubsts, GeneratorSubsts}; -use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; - -use rustc_hir::def_id::DefId; -use rustc_macros::HashStable; -use rustc_serialize::{self, Decodable, Decoder, Encodable, Encoder}; -use rustc_span::{Span, DUMMY_SP}; -use smallvec::SmallVec; - -use core::intrinsics; -use std::cmp::Ordering; -use std::fmt; -use std::marker::PhantomData; -use std::mem; -use std::num::NonZeroUsize; - -/// An entity in the Rust type system, which can be one of -/// several kinds (types, lifetimes, and consts). -/// To reduce memory usage, a `GenericArg` is a interned pointer, -/// with the lowest 2 bits being reserved for a tag to -/// indicate the type (`Ty`, `Region`, or `Const`) it points to. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct GenericArg<'tcx> { - ptr: NonZeroUsize, - marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, &'tcx ty::Const<'tcx>)>, -} - -const TAG_MASK: usize = 0b11; -const TYPE_TAG: usize = 0b00; -const REGION_TAG: usize = 0b01; -const CONST_TAG: usize = 0b10; - -#[derive(Debug, RustcEncodable, RustcDecodable, PartialEq, Eq, PartialOrd, Ord, HashStable)] -pub enum GenericArgKind<'tcx> { - Lifetime(ty::Region<'tcx>), - Type(Ty<'tcx>), - Const(&'tcx ty::Const<'tcx>), -} - -impl<'tcx> GenericArgKind<'tcx> { - fn pack(self) -> GenericArg<'tcx> { - let (tag, ptr) = match self { - GenericArgKind::Lifetime(lt) => { - // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(lt) & TAG_MASK, 0); - (REGION_TAG, lt as *const _ as usize) - } - GenericArgKind::Type(ty) => { - // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0); - (TYPE_TAG, ty as *const _ as usize) - } - GenericArgKind::Const(ct) => { - // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(ct) & TAG_MASK, 0); - (CONST_TAG, ct as *const _ as usize) - } - }; - - GenericArg { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData } - } -} - -impl fmt::Debug for GenericArg<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.unpack() { - GenericArgKind::Lifetime(lt) => lt.fmt(f), - GenericArgKind::Type(ty) => ty.fmt(f), - GenericArgKind::Const(ct) => ct.fmt(f), - } - } -} - -impl<'tcx> Ord for GenericArg<'tcx> { - fn cmp(&self, other: &GenericArg<'_>) -> Ordering { - self.unpack().cmp(&other.unpack()) - } -} - -impl<'tcx> PartialOrd for GenericArg<'tcx> { - fn partial_cmp(&self, other: &GenericArg<'_>) -> Option<Ordering> { - Some(self.cmp(&other)) - } -} - -impl<'tcx> From<ty::Region<'tcx>> for GenericArg<'tcx> { - fn from(r: ty::Region<'tcx>) -> GenericArg<'tcx> { - GenericArgKind::Lifetime(r).pack() - } -} - -impl<'tcx> From<Ty<'tcx>> for GenericArg<'tcx> { - fn from(ty: Ty<'tcx>) -> GenericArg<'tcx> { - GenericArgKind::Type(ty).pack() - } -} - -impl<'tcx> From<&'tcx ty::Const<'tcx>> for GenericArg<'tcx> { - fn from(c: &'tcx ty::Const<'tcx>) -> GenericArg<'tcx> { - GenericArgKind::Const(c).pack() - } -} - -impl<'tcx> GenericArg<'tcx> { - #[inline] - pub fn unpack(self) -> GenericArgKind<'tcx> { - let ptr = self.ptr.get(); - unsafe { - match ptr & TAG_MASK { - REGION_TAG => GenericArgKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)), - TYPE_TAG => GenericArgKind::Type(&*((ptr & !TAG_MASK) as *const _)), - CONST_TAG => GenericArgKind::Const(&*((ptr & !TAG_MASK) as *const _)), - _ => intrinsics::unreachable(), - } - } - } - - /// Unpack the `GenericArg` as a type when it is known certainly to be a type. - /// This is true in cases where `Substs` is used in places where the kinds are known - /// to be limited (e.g. in tuples, where the only parameters are type parameters). - pub fn expect_ty(self) -> Ty<'tcx> { - match self.unpack() { - GenericArgKind::Type(ty) => ty, - _ => bug!("expected a type, but found another kind"), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> { - type Lifted = GenericArg<'tcx>; - - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match self.unpack() { - GenericArgKind::Lifetime(lt) => tcx.lift(<).map(|lt| lt.into()), - GenericArgKind::Type(ty) => tcx.lift(&ty).map(|ty| ty.into()), - GenericArgKind::Const(ct) => tcx.lift(&ct).map(|ct| ct.into()), - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - match self.unpack() { - GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(), - GenericArgKind::Type(ty) => ty.fold_with(folder).into(), - GenericArgKind::Const(ct) => ct.fold_with(folder).into(), - } - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - match self.unpack() { - GenericArgKind::Lifetime(lt) => lt.visit_with(visitor), - GenericArgKind::Type(ty) => ty.visit_with(visitor), - GenericArgKind::Const(ct) => ct.visit_with(visitor), - } - } -} - -impl<'tcx> Encodable for GenericArg<'tcx> { - fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> { - self.unpack().encode(e) - } -} - -impl<'tcx> Decodable for GenericArg<'tcx> { - fn decode<D: Decoder>(d: &mut D) -> Result<GenericArg<'tcx>, D::Error> { - Ok(GenericArgKind::decode(d)?.pack()) - } -} - -/// A substitution mapping generic parameters to new values. -pub type InternalSubsts<'tcx> = List<GenericArg<'tcx>>; - -pub type SubstsRef<'tcx> = &'tcx InternalSubsts<'tcx>; - -impl<'a, 'tcx> InternalSubsts<'tcx> { - /// Interpret these substitutions as the substitutions of a closure type. - /// Closure substitutions have a particular structure controlled by the - /// compiler that encodes information like the signature and closure kind; - /// see `ty::ClosureSubsts` struct for more comments. - pub fn as_closure(&'a self) -> ClosureSubsts<'a> { - ClosureSubsts { substs: self } - } - - /// Interpret these substitutions as the substitutions of a generator type. - /// Closure substitutions have a particular structure controlled by the - /// compiler that encodes information like the signature and generator kind; - /// see `ty::GeneratorSubsts` struct for more comments. - pub fn as_generator(&'tcx self) -> GeneratorSubsts<'tcx> { - GeneratorSubsts { substs: self } - } - - /// Creates a `InternalSubsts` that maps each generic parameter to itself. - pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { - Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param)) - } - - /// Creates a `InternalSubsts` that maps each generic parameter to a higher-ranked - /// var bound at index `0`. For types, we use a `BoundVar` index equal to - /// the type parameter index. For regions, we use the `BoundRegion::BrNamed` - /// variant (which has a `DefId`). - pub fn bound_vars_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { - Self::for_item(tcx, def_id, |param, _| match param.kind { - ty::GenericParamDefKind::Type { .. } => tcx - .mk_ty(ty::Bound( - ty::INNERMOST, - ty::BoundTy { - var: ty::BoundVar::from(param.index), - kind: ty::BoundTyKind::Param(param.name), - }, - )) - .into(), - - ty::GenericParamDefKind::Lifetime => tcx - .mk_region(ty::RegionKind::ReLateBound( - ty::INNERMOST, - ty::BoundRegion::BrNamed(param.def_id, param.name), - )) - .into(), - - ty::GenericParamDefKind::Const => tcx - .mk_const(ty::Const { - val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)), - ty: tcx.type_of(param.def_id), - }) - .into(), - }) - } - - /// Creates a `InternalSubsts` for generic parameter definitions, - /// by calling closures to obtain each kind. - /// The closures get to observe the `InternalSubsts` as they're - /// being built, which can be used to correctly - /// substitute defaults of generic parameters. - pub fn for_item<F>(tcx: TyCtxt<'tcx>, def_id: DefId, mut mk_kind: F) -> SubstsRef<'tcx> - where - F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>, - { - let defs = tcx.generics_of(def_id); - let count = defs.count(); - let mut substs = SmallVec::with_capacity(count); - Self::fill_item(&mut substs, tcx, defs, &mut mk_kind); - tcx.intern_substs(&substs) - } - - pub fn extend_to<F>(&self, tcx: TyCtxt<'tcx>, def_id: DefId, mut mk_kind: F) -> SubstsRef<'tcx> - where - F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>, - { - Self::for_item(tcx, def_id, |param, substs| { - self.get(param.index as usize).cloned().unwrap_or_else(|| mk_kind(param, substs)) - }) - } - - fn fill_item<F>( - substs: &mut SmallVec<[GenericArg<'tcx>; 8]>, - tcx: TyCtxt<'tcx>, - defs: &ty::Generics, - mk_kind: &mut F, - ) where - F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>, - { - if let Some(def_id) = defs.parent { - let parent_defs = tcx.generics_of(def_id); - Self::fill_item(substs, tcx, parent_defs, mk_kind); - } - Self::fill_single(substs, defs, mk_kind) - } - - fn fill_single<F>( - substs: &mut SmallVec<[GenericArg<'tcx>; 8]>, - defs: &ty::Generics, - mk_kind: &mut F, - ) where - F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>, - { - substs.reserve(defs.params.len()); - for param in &defs.params { - let kind = mk_kind(param, substs); - assert_eq!(param.index as usize, substs.len()); - substs.push(kind); - } - } - - pub fn is_noop(&self) -> bool { - self.is_empty() - } - - #[inline] - pub fn types(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a { - self.iter() - .filter_map(|k| if let GenericArgKind::Type(ty) = k.unpack() { Some(ty) } else { None }) - } - - #[inline] - pub fn regions(&'a self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> + 'a { - self.iter().filter_map(|k| { - if let GenericArgKind::Lifetime(lt) = k.unpack() { Some(lt) } else { None } - }) - } - - #[inline] - pub fn consts(&'a self) -> impl DoubleEndedIterator<Item = &'tcx ty::Const<'tcx>> + 'a { - self.iter().filter_map(|k| { - if let GenericArgKind::Const(ct) = k.unpack() { Some(ct) } else { None } - }) - } - - #[inline] - pub fn non_erasable_generics( - &'a self, - ) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> + 'a { - self.iter().filter_map(|k| match k.unpack() { - GenericArgKind::Lifetime(_) => None, - generic => Some(generic), - }) - } - - #[inline] - pub fn type_at(&self, i: usize) -> Ty<'tcx> { - if let GenericArgKind::Type(ty) = self[i].unpack() { - ty - } else { - bug!("expected type for param #{} in {:?}", i, self); - } - } - - #[inline] - pub fn region_at(&self, i: usize) -> ty::Region<'tcx> { - if let GenericArgKind::Lifetime(lt) = self[i].unpack() { - lt - } else { - bug!("expected region for param #{} in {:?}", i, self); - } - } - - #[inline] - pub fn const_at(&self, i: usize) -> &'tcx ty::Const<'tcx> { - if let GenericArgKind::Const(ct) = self[i].unpack() { - ct - } else { - bug!("expected const for param #{} in {:?}", i, self); - } - } - - #[inline] - pub fn type_for_def(&self, def: &ty::GenericParamDef) -> GenericArg<'tcx> { - self.type_at(def.index as usize).into() - } - - /// Transform from substitutions for a child of `source_ancestor` - /// (e.g., a trait or impl) to substitutions for the same child - /// in a different item, with `target_substs` as the base for - /// the target impl/trait, with the source child-specific - /// parameters (e.g., method parameters) on top of that base. - pub fn rebase_onto( - &self, - tcx: TyCtxt<'tcx>, - source_ancestor: DefId, - target_substs: SubstsRef<'tcx>, - ) -> SubstsRef<'tcx> { - let defs = tcx.generics_of(source_ancestor); - tcx.mk_substs(target_substs.iter().chain(&self[defs.params.len()..]).cloned()) - } - - pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsRef<'tcx> { - tcx.mk_substs(self.iter().take(generics.count()).cloned()) - } -} - -impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - // This code is hot enough that it's worth specializing for the most - // common length lists, to avoid the overhead of `SmallVec` creation. - // The match arms are in order of frequency. The 1, 2, and 0 cases are - // typically hit in 90--99.99% of cases. When folding doesn't change - // the substs, it's faster to reuse the existing substs rather than - // calling `intern_substs`. - match self.len() { - 1 => { - let param0 = self[0].fold_with(folder); - if param0 == self[0] { self } else { folder.tcx().intern_substs(&[param0]) } - } - 2 => { - let param0 = self[0].fold_with(folder); - let param1 = self[1].fold_with(folder); - if param0 == self[0] && param1 == self[1] { - self - } else { - folder.tcx().intern_substs(&[param0, param1]) - } - } - 0 => self, - _ => { - let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect(); - if params[..] == self[..] { self } else { folder.tcx().intern_substs(¶ms) } - } - } - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx> rustc_serialize::UseSpecializedDecodable for SubstsRef<'tcx> {} - -/////////////////////////////////////////////////////////////////////////// -// Public trait `Subst` -// -// Just call `foo.subst(tcx, substs)` to perform a substitution across -// `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when -// there is more information available (for better errors). - -pub trait Subst<'tcx>: Sized { - fn subst(&self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self { - self.subst_spanned(tcx, substs, None) - } - - fn subst_spanned( - &self, - tcx: TyCtxt<'tcx>, - substs: &[GenericArg<'tcx>], - span: Option<Span>, - ) -> Self; -} - -impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T { - fn subst_spanned( - &self, - tcx: TyCtxt<'tcx>, - substs: &[GenericArg<'tcx>], - span: Option<Span>, - ) -> T { - let mut folder = - SubstFolder { tcx, substs, span, root_ty: None, ty_stack_depth: 0, binders_passed: 0 }; - (*self).fold_with(&mut folder) - } -} - -/////////////////////////////////////////////////////////////////////////// -// The actual substitution engine itself is a type folder. - -struct SubstFolder<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - substs: &'a [GenericArg<'tcx>], - - /// The location for which the substitution is performed, if available. - span: Option<Span>, - - /// The root type that is being substituted, if available. - root_ty: Option<Ty<'tcx>>, - - /// Depth of type stack - ty_stack_depth: usize, - - /// Number of region binders we have passed through while doing the substitution - binders_passed: u32, -} - -impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> { - self.binders_passed += 1; - let t = t.super_fold_with(self); - self.binders_passed -= 1; - t - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - // Note: This routine only handles regions that are bound on - // type declarations and other outer declarations, not those - // bound in *fn types*. Region substitution of the bound - // regions that appear in a function signature is done using - // the specialized routine `ty::replace_late_regions()`. - match *r { - ty::ReEarlyBound(data) => { - let rk = self.substs.get(data.index as usize).map(|k| k.unpack()); - match rk { - Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt), - _ => { - let span = self.span.unwrap_or(DUMMY_SP); - let msg = format!( - "Region parameter out of range \ - when substituting in region {} (root type={:?}) \ - (index={})", - data.name, self.root_ty, data.index - ); - span_bug!(span, "{}", msg); - } - } - } - _ => r, - } - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_subst() { - return t; - } - - // track the root type we were asked to substitute - let depth = self.ty_stack_depth; - if depth == 0 { - self.root_ty = Some(t); - } - self.ty_stack_depth += 1; - - let t1 = match t.kind { - ty::Param(p) => self.ty_for_param(p, t), - _ => t.super_fold_with(self), - }; - - assert_eq!(depth + 1, self.ty_stack_depth); - self.ty_stack_depth -= 1; - if depth == 0 { - self.root_ty = None; - } - - return t1; - } - - fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if !c.needs_subst() { - return c; - } - - if let ty::ConstKind::Param(p) = c.val { - self.const_for_param(p, c) - } else { - c.super_fold_with(self) - } - } -} - -impl<'a, 'tcx> SubstFolder<'a, 'tcx> { - fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> { - // Look up the type in the substitutions. It really should be in there. - let opt_ty = self.substs.get(p.index as usize).map(|k| k.unpack()); - let ty = match opt_ty { - Some(GenericArgKind::Type(ty)) => ty, - Some(kind) => { - let span = self.span.unwrap_or(DUMMY_SP); - span_bug!( - span, - "expected type for `{:?}` ({:?}/{}) but found {:?} \ - when substituting (root type={:?}) substs={:?}", - p, - source_ty, - p.index, - kind, - self.root_ty, - self.substs, - ); - } - None => { - let span = self.span.unwrap_or(DUMMY_SP); - span_bug!( - span, - "type parameter `{:?}` ({:?}/{}) out of range \ - when substituting (root type={:?}) substs={:?}", - p, - source_ty, - p.index, - self.root_ty, - self.substs, - ); - } - }; - - self.shift_vars_through_binders(ty) - } - - fn const_for_param( - &self, - p: ParamConst, - source_ct: &'tcx ty::Const<'tcx>, - ) -> &'tcx ty::Const<'tcx> { - // Look up the const in the substitutions. It really should be in there. - let opt_ct = self.substs.get(p.index as usize).map(|k| k.unpack()); - let ct = match opt_ct { - Some(GenericArgKind::Const(ct)) => ct, - Some(kind) => { - let span = self.span.unwrap_or(DUMMY_SP); - span_bug!( - span, - "expected const for `{:?}` ({:?}/{}) but found {:?} \ - when substituting substs={:?}", - p, - source_ct, - p.index, - kind, - self.substs, - ); - } - None => { - let span = self.span.unwrap_or(DUMMY_SP); - span_bug!( - span, - "const parameter `{:?}` ({:?}/{}) out of range \ - when substituting substs={:?}", - p, - source_ct, - p.index, - self.substs, - ); - } - }; - - self.shift_vars_through_binders(ct) - } - - /// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs - /// when we are substituting a type with escaping bound vars into a context where we have - /// passed through binders. That's quite a mouthful. Let's see an example: - /// - /// ``` - /// type Func<A> = fn(A); - /// type MetaFunc = for<'a> fn(Func<&'a int>) - /// ``` - /// - /// The type `MetaFunc`, when fully expanded, will be - /// - /// for<'a> fn(fn(&'a int)) - /// ^~ ^~ ^~~ - /// | | | - /// | | DebruijnIndex of 2 - /// Binders - /// - /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the - /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip - /// over the inner binder (remember that we count De Bruijn indices from 1). However, in the - /// definition of `MetaFunc`, the binder is not visible, so the type `&'a int` will have a - /// De Bruijn index of 1. It's only during the substitution that we can see we must increase the - /// depth by 1 to account for the binder that we passed through. - /// - /// As a second example, consider this twist: - /// - /// ``` - /// type FuncTuple<A> = (A,fn(A)); - /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a int>) - /// ``` - /// - /// Here the final type will be: - /// - /// for<'a> fn((&'a int, fn(&'a int))) - /// ^~~ ^~~ - /// | | - /// DebruijnIndex of 1 | - /// DebruijnIndex of 2 - /// - /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the - /// first case we do not increase the De Bruijn index and in the second case we do. The reason - /// is that only in the second case have we passed through a fn binder. - fn shift_vars_through_binders<T: TypeFoldable<'tcx>>(&self, val: T) -> T { - debug!( - "shift_vars(val={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})", - val, - self.binders_passed, - val.has_escaping_bound_vars() - ); - - if self.binders_passed == 0 || !val.has_escaping_bound_vars() { - return val; - } - - let result = ty::fold::shift_vars(self.tcx(), &val, self.binders_passed); - debug!("shift_vars: shifted result = {:?}", result); - - result - } - - fn shift_region_through_binders(&self, region: ty::Region<'tcx>) -> ty::Region<'tcx> { - if self.binders_passed == 0 || !region.has_escaping_bound_vars() { - return region; - } - ty::fold::shift_region(self.tcx, region, self.binders_passed) - } -} - -pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>; - -/// Stores the user-given substs to reach some fully qualified path -/// (e.g., `<T>::Item` or `<T as Trait>::Item`). -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable, Lift)] -pub struct UserSubsts<'tcx> { - /// The substitutions for the item as given by the user. - pub substs: SubstsRef<'tcx>, - - /// The self type, in the case of a `<T>::Item` path (when applied - /// to an inherent impl). See `UserSelfTy` below. - pub user_self_ty: Option<UserSelfTy<'tcx>>, -} - -/// Specifies the user-given self type. In the case of a path that -/// refers to a member in an inherent impl, this self type is -/// sometimes needed to constrain the type parameters on the impl. For -/// example, in this code: -/// -/// ``` -/// struct Foo<T> { } -/// impl<A> Foo<A> { fn method() { } } -/// ``` -/// -/// when you then have a path like `<Foo<&'static u32>>::method`, -/// this struct would carry the `DefId` of the impl along with the -/// self type `Foo<u32>`. Then we can instantiate the parameters of -/// the impl (with the substs from `UserSubsts`) and apply those to -/// the self type, giving `Foo<?A>`. Finally, we unify that with -/// the self type here, which contains `?A` to be `&'static u32` -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -#[derive(HashStable, TypeFoldable, Lift)] -pub struct UserSelfTy<'tcx> { - pub impl_def_id: DefId, - pub self_ty: Ty<'tcx>, -} diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs deleted file mode 100644 index 0cf1c397648..00000000000 --- a/src/librustc/ty/trait_def.rs +++ /dev/null @@ -1,191 +0,0 @@ -use crate::hir::map::DefPathHash; -use crate::ich::{self, StableHashingContext}; -use crate::traits::specialization_graph; -use crate::ty::fast_reject; -use crate::ty::fold::TypeFoldable; -use crate::ty::{Ty, TyCtxt}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; - -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_macros::HashStable; - -/// A trait's definition with type information. -#[derive(HashStable)] -pub struct TraitDef { - // We already have the def_path_hash below, no need to hash it twice - #[stable_hasher(ignore)] - pub def_id: DefId, - - pub unsafety: hir::Unsafety, - - /// If `true`, then this trait had the `#[rustc_paren_sugar]` - /// attribute, indicating that it should be used with `Foo()` - /// sugar. This is a temporary thing -- eventually any trait will - /// be usable with the sugar (or without it). - pub paren_sugar: bool, - - pub has_auto_impl: bool, - - /// If `true`, then this trait has the `#[marker]` attribute, indicating - /// that all its associated items have defaults that cannot be overridden, - /// and thus `impl`s of it are allowed to overlap. - pub is_marker: bool, - - /// The ICH of this trait's DefPath, cached here so it doesn't have to be - /// recomputed all the time. - pub def_path_hash: DefPathHash, -} - -#[derive(Default)] -pub struct TraitImpls { - blanket_impls: Vec<DefId>, - /// Impls indexed by their simplified self type, for fast lookup. - non_blanket_impls: FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>, -} - -impl<'tcx> TraitDef { - pub fn new( - def_id: DefId, - unsafety: hir::Unsafety, - paren_sugar: bool, - has_auto_impl: bool, - is_marker: bool, - def_path_hash: DefPathHash, - ) -> TraitDef { - TraitDef { def_id, unsafety, paren_sugar, has_auto_impl, is_marker, def_path_hash } - } - - pub fn ancestors( - &self, - tcx: TyCtxt<'tcx>, - of_impl: DefId, - ) -> specialization_graph::Ancestors<'tcx> { - specialization_graph::ancestors(tcx, self.def_id, of_impl) - } -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn for_each_impl<F: FnMut(DefId)>(self, def_id: DefId, mut f: F) { - let impls = self.trait_impls_of(def_id); - - for &impl_def_id in impls.blanket_impls.iter() { - f(impl_def_id); - } - - for v in impls.non_blanket_impls.values() { - for &impl_def_id in v { - f(impl_def_id); - } - } - } - - /// Iterate over every impl that could possibly match the - /// self type `self_ty`. - pub fn for_each_relevant_impl<F: FnMut(DefId)>( - self, - def_id: DefId, - self_ty: Ty<'tcx>, - mut f: F, - ) { - let impls = self.trait_impls_of(def_id); - - for &impl_def_id in impls.blanket_impls.iter() { - f(impl_def_id); - } - - // simplify_type(.., false) basically replaces type parameters and - // projections with infer-variables. This is, of course, done on - // the impl trait-ref when it is instantiated, but not on the - // predicate trait-ref which is passed here. - // - // for example, if we match `S: Copy` against an impl like - // `impl<T:Copy> Copy for Option<T>`, we replace the type variable - // in `Option<T>` with an infer variable, to `Option<_>` (this - // doesn't actually change fast_reject output), but we don't - // replace `S` with anything - this impl of course can't be - // selected, and as there are hundreds of similar impls, - // considering them would significantly harm performance. - - // This depends on the set of all impls for the trait. That is - // unfortunate. When we get red-green recompilation, we would like - // to have a way of knowing whether the set of relevant impls - // changed. The most naive - // way would be to compute the Vec of relevant impls and see whether - // it differs between compilations. That shouldn't be too slow by - // itself - we do quite a bit of work for each relevant impl anyway. - // - // If we want to be faster, we could have separate queries for - // blanket and non-blanket impls, and compare them separately. - // - // I think we'll cross that bridge when we get to it. - if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) { - if let Some(impls) = impls.non_blanket_impls.get(&simp) { - for &impl_def_id in impls { - f(impl_def_id); - } - } - } else { - for &impl_def_id in impls.non_blanket_impls.values().flatten() { - f(impl_def_id); - } - } - } - - /// Returns a vector containing all impls - pub fn all_impls(self, def_id: DefId) -> Vec<DefId> { - let impls = self.trait_impls_of(def_id); - - impls - .blanket_impls - .iter() - .chain(impls.non_blanket_impls.values().flatten()) - .cloned() - .collect() - } -} - -// Query provider for `trait_impls_of`. -pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> &TraitImpls { - let mut impls = TraitImpls::default(); - - { - let mut add_impl = |impl_def_id| { - let impl_self_ty = tcx.type_of(impl_def_id); - if impl_def_id.is_local() && impl_self_ty.references_error() { - return; - } - - if let Some(simplified_self_ty) = fast_reject::simplify_type(tcx, impl_self_ty, false) { - impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id); - } else { - impls.blanket_impls.push(impl_def_id); - } - }; - - // Traits defined in the current crate can't have impls in upstream - // crates, so we don't bother querying the cstore. - if !trait_id.is_local() { - for &cnum in tcx.crates().iter() { - for &def_id in tcx.implementations_of_trait((cnum, trait_id)).iter() { - add_impl(def_id); - } - } - } - - for &hir_id in tcx.hir().trait_impls(trait_id) { - add_impl(tcx.hir().local_def_id(hir_id)); - } - } - - tcx.arena.alloc(impls) -} - -impl<'a> HashStable<StableHashingContext<'a>> for TraitImpls { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let TraitImpls { ref blanket_impls, ref non_blanket_impls } = *self; - - ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, non_blanket_impls); - } -} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs deleted file mode 100644 index eec6893d357..00000000000 --- a/src/librustc/ty/util.rs +++ /dev/null @@ -1,1096 +0,0 @@ -//! Miscellaneous type-system utilities that are too small to deserve their own modules. - -use crate::hir::map::DefPathData; -use crate::ich::NodeIdHashingMode; -use crate::mir::interpret::{sign_extend, truncate}; -use crate::ty::layout::{Integer, IntegerExt, Size}; -use crate::ty::query::TyCtxtAt; -use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef}; -use crate::ty::TyKind::*; -use crate::ty::{self, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable}; -use crate::util::common::ErrorReported; -use rustc_apfloat::Float as _; -use rustc_attr::{self as attr, SignedInt, UnsignedInt}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir as hir; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; -use rustc_macros::HashStable; -use rustc_span::Span; -use rustc_target::abi::TargetDataLayout; -use smallvec::SmallVec; -use std::{cmp, fmt}; -use syntax::ast; - -#[derive(Copy, Clone, Debug)] -pub struct Discr<'tcx> { - /// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`). - pub val: u128, - pub ty: Ty<'tcx>, -} - -impl<'tcx> fmt::Display for Discr<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.ty.kind { - ty::Int(ity) => { - let size = ty::tls::with(|tcx| Integer::from_attr(&tcx, SignedInt(ity)).size()); - let x = self.val; - // sign extend the raw representation to be an i128 - let x = sign_extend(x, size) as i128; - write!(fmt, "{}", x) - } - _ => write!(fmt, "{}", self.val), - } - } -} - -fn signed_min(size: Size) -> i128 { - sign_extend(1_u128 << (size.bits() - 1), size) as i128 -} - -fn signed_max(size: Size) -> i128 { - i128::max_value() >> (128 - size.bits()) -} - -fn unsigned_max(size: Size) -> u128 { - u128::max_value() >> (128 - size.bits()) -} - -fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) { - let (int, signed) = match ty.kind { - Int(ity) => (Integer::from_attr(&tcx, SignedInt(ity)), true), - Uint(uty) => (Integer::from_attr(&tcx, UnsignedInt(uty)), false), - _ => bug!("non integer discriminant"), - }; - (int.size(), signed) -} - -impl<'tcx> Discr<'tcx> { - /// Adds `1` to the value and wraps around if the maximum for the type is reached. - pub fn wrap_incr(self, tcx: TyCtxt<'tcx>) -> Self { - self.checked_add(tcx, 1).0 - } - pub fn checked_add(self, tcx: TyCtxt<'tcx>, n: u128) -> (Self, bool) { - let (size, signed) = int_size_and_signed(tcx, self.ty); - let (val, oflo) = if signed { - let min = signed_min(size); - let max = signed_max(size); - let val = sign_extend(self.val, size) as i128; - assert!(n < (i128::max_value() as u128)); - let n = n as i128; - let oflo = val > max - n; - let val = if oflo { min + (n - (max - val) - 1) } else { val + n }; - // zero the upper bits - let val = val as u128; - let val = truncate(val, size); - (val, oflo) - } else { - let max = unsigned_max(size); - let val = self.val; - let oflo = val > max - n; - let val = if oflo { n - (max - val) - 1 } else { val + n }; - (val, oflo) - }; - (Self { val, ty: self.ty }, oflo) - } -} - -pub trait IntTypeExt { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; - fn disr_incr<'tcx>(&self, tcx: TyCtxt<'tcx>, val: Option<Discr<'tcx>>) -> Option<Discr<'tcx>>; - fn initial_discriminant<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Discr<'tcx>; -} - -impl IntTypeExt for attr::IntType { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match *self { - SignedInt(ast::IntTy::I8) => tcx.types.i8, - SignedInt(ast::IntTy::I16) => tcx.types.i16, - SignedInt(ast::IntTy::I32) => tcx.types.i32, - SignedInt(ast::IntTy::I64) => tcx.types.i64, - SignedInt(ast::IntTy::I128) => tcx.types.i128, - SignedInt(ast::IntTy::Isize) => tcx.types.isize, - UnsignedInt(ast::UintTy::U8) => tcx.types.u8, - UnsignedInt(ast::UintTy::U16) => tcx.types.u16, - UnsignedInt(ast::UintTy::U32) => tcx.types.u32, - UnsignedInt(ast::UintTy::U64) => tcx.types.u64, - UnsignedInt(ast::UintTy::U128) => tcx.types.u128, - UnsignedInt(ast::UintTy::Usize) => tcx.types.usize, - } - } - - fn initial_discriminant<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Discr<'tcx> { - Discr { val: 0, ty: self.to_ty(tcx) } - } - - fn disr_incr<'tcx>(&self, tcx: TyCtxt<'tcx>, val: Option<Discr<'tcx>>) -> Option<Discr<'tcx>> { - if let Some(val) = val { - assert_eq!(self.to_ty(tcx), val.ty); - let (new, oflo) = val.checked_add(tcx, 1); - if oflo { None } else { Some(new) } - } else { - Some(self.initial_discriminant(tcx)) - } - } -} - -/// Describes whether a type is representable. For types that are not -/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to -/// distinguish between types that are recursive with themselves and types that -/// contain a different recursive type. These cases can therefore be treated -/// differently when reporting errors. -/// -/// The ordering of the cases is significant. They are sorted so that cmp::max -/// will keep the "more erroneous" of two values. -#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] -pub enum Representability { - Representable, - ContainsRecursive, - SelfRecursive(Vec<Span>), -} - -impl<'tcx> TyCtxt<'tcx> { - /// Creates a hash of the type `Ty` which will be the same no matter what crate - /// context it's calculated within. This is used by the `type_id` intrinsic. - pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { - let mut hasher = StableHasher::new(); - let mut hcx = self.create_stable_hashing_context(); - - // We want the type_id be independent of the types free regions, so we - // erase them. The erase_regions() call will also anonymize bound - // regions, which is desirable too. - let ty = self.erase_regions(&ty); - - hcx.while_hashing_spans(false, |hcx| { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - ty.hash_stable(hcx, &mut hasher); - }); - }); - hasher.finish() - } -} - -impl<'tcx> TyCtxt<'tcx> { - pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { - if let ty::Adt(def, substs) = ty.kind { - for field in def.all_fields() { - let field_ty = field.ty(self, substs); - if let Error = field_ty.kind { - return true; - } - } - } - false - } - - /// Attempts to returns the deeply last field of nested structures, but - /// does not apply any normalization in its search. Returns the same type - /// if input `ty` is not a structure at all. - pub fn struct_tail_without_normalization(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let tcx = self; - tcx.struct_tail_with_normalize(ty, |ty| ty) - } - - /// Returns the deeply last field of nested structures, or the same type if - /// not a structure at all. Corresponds to the only possible unsized field, - /// and its type can be used to determine unsizing strategy. - /// - /// Should only be called if `ty` has no inference variables and does not - /// need its lifetimes preserved (e.g. as part of codegen); otherwise - /// normalization attempt may cause compiler bugs. - pub fn struct_tail_erasing_lifetimes( - self, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Ty<'tcx> { - let tcx = self; - tcx.struct_tail_with_normalize(ty, |ty| tcx.normalize_erasing_regions(param_env, ty)) - } - - /// Returns the deeply last field of nested structures, or the same type if - /// not a structure at all. Corresponds to the only possible unsized field, - /// and its type can be used to determine unsizing strategy. - /// - /// This is parameterized over the normalization strategy (i.e. how to - /// handle `<T as Trait>::Assoc` and `impl Trait`); pass the identity - /// function to indicate no normalization should take place. - /// - /// See also `struct_tail_erasing_lifetimes`, which is suitable for use - /// during codegen. - pub fn struct_tail_with_normalize( - self, - mut ty: Ty<'tcx>, - normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>, - ) -> Ty<'tcx> { - loop { - match ty.kind { - ty::Adt(def, substs) => { - if !def.is_struct() { - break; - } - match def.non_enum_variant().fields.last() { - Some(f) => ty = f.ty(self, substs), - None => break, - } - } - - ty::Tuple(tys) => { - if let Some((&last_ty, _)) = tys.split_last() { - ty = last_ty.expect_ty(); - } else { - break; - } - } - - ty::Projection(_) | ty::Opaque(..) => { - let normalized = normalize(ty); - if ty == normalized { - return ty; - } else { - ty = normalized; - } - } - - _ => { - break; - } - } - } - ty - } - - /// Same as applying `struct_tail` on `source` and `target`, but only - /// keeps going as long as the two types are instances of the same - /// structure definitions. - /// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`, - /// whereas struct_tail produces `T`, and `Trait`, respectively. - /// - /// Should only be called if the types have no inference variables and do - /// not need their lifetimes preserved (e.g., as part of codegen); otherwise, - /// normalization attempt may cause compiler bugs. - pub fn struct_lockstep_tails_erasing_lifetimes( - self, - source: Ty<'tcx>, - target: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> (Ty<'tcx>, Ty<'tcx>) { - let tcx = self; - tcx.struct_lockstep_tails_with_normalize(source, target, |ty| { - tcx.normalize_erasing_regions(param_env, ty) - }) - } - - /// Same as applying `struct_tail` on `source` and `target`, but only - /// keeps going as long as the two types are instances of the same - /// structure definitions. - /// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`, - /// whereas struct_tail produces `T`, and `Trait`, respectively. - /// - /// See also `struct_lockstep_tails_erasing_lifetimes`, which is suitable for use - /// during codegen. - pub fn struct_lockstep_tails_with_normalize( - self, - source: Ty<'tcx>, - target: Ty<'tcx>, - normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>, - ) -> (Ty<'tcx>, Ty<'tcx>) { - let (mut a, mut b) = (source, target); - loop { - match (&a.kind, &b.kind) { - (&Adt(a_def, a_substs), &Adt(b_def, b_substs)) - if a_def == b_def && a_def.is_struct() => - { - if let Some(f) = a_def.non_enum_variant().fields.last() { - a = f.ty(self, a_substs); - b = f.ty(self, b_substs); - } else { - break; - } - } - (&Tuple(a_tys), &Tuple(b_tys)) if a_tys.len() == b_tys.len() => { - if let Some(a_last) = a_tys.last() { - a = a_last.expect_ty(); - b = b_tys.last().unwrap().expect_ty(); - } else { - break; - } - } - (ty::Projection(_), _) - | (ty::Opaque(..), _) - | (_, ty::Projection(_)) - | (_, ty::Opaque(..)) => { - // If either side is a projection, attempt to - // progress via normalization. (Should be safe to - // apply to both sides as normalization is - // idempotent.) - let a_norm = normalize(a); - let b_norm = normalize(b); - if a == a_norm && b == b_norm { - break; - } else { - a = a_norm; - b = b_norm; - } - } - - _ => break, - } - } - (a, b) - } - - /// Calculate the destructor of a given type. - pub fn calculate_dtor( - self, - adt_did: DefId, - validate: &mut dyn FnMut(Self, DefId) -> Result<(), ErrorReported>, - ) -> Option<ty::Destructor> { - let drop_trait = if let Some(def_id) = self.lang_items().drop_trait() { - def_id - } else { - return None; - }; - - self.ensure().coherent_trait(drop_trait); - - let mut dtor_did = None; - let ty = self.type_of(adt_did); - self.for_each_relevant_impl(drop_trait, ty, |impl_did| { - if let Some(item) = self.associated_items(impl_did).in_definition_order().nth(0) { - if validate(self, impl_did).is_ok() { - dtor_did = Some(item.def_id); - } - } - }); - - Some(ty::Destructor { did: dtor_did? }) - } - - /// Returns the set of types that are required to be alive in - /// order to run the destructor of `def` (see RFCs 769 and - /// 1238). - /// - /// Note that this returns only the constraints for the - /// destructor of `def` itself. For the destructors of the - /// contents, you need `adt_dtorck_constraint`. - pub fn destructor_constraints(self, def: &'tcx ty::AdtDef) -> Vec<ty::subst::GenericArg<'tcx>> { - let dtor = match def.destructor(self) { - None => { - debug!("destructor_constraints({:?}) - no dtor", def.did); - return vec![]; - } - Some(dtor) => dtor.did, - }; - - let impl_def_id = self.associated_item(dtor).container.id(); - let impl_generics = self.generics_of(impl_def_id); - - // We have a destructor - all the parameters that are not - // pure_wrt_drop (i.e, don't have a #[may_dangle] attribute) - // must be live. - - // We need to return the list of parameters from the ADTs - // generics/substs that correspond to impure parameters on the - // impl's generics. This is a bit ugly, but conceptually simple: - // - // Suppose our ADT looks like the following - // - // struct S<X, Y, Z>(X, Y, Z); - // - // and the impl is - // - // impl<#[may_dangle] P0, P1, P2> Drop for S<P1, P2, P0> - // - // We want to return the parameters (X, Y). For that, we match - // up the item-substs <X, Y, Z> with the substs on the impl ADT, - // <P1, P2, P0>, and then look up which of the impl substs refer to - // parameters marked as pure. - - let impl_substs = match self.type_of(impl_def_id).kind { - ty::Adt(def_, substs) if def_ == def => substs, - _ => bug!(), - }; - - let item_substs = match self.type_of(def.did).kind { - ty::Adt(def_, substs) if def_ == def => substs, - _ => bug!(), - }; - - let result = item_substs - .iter() - .zip(impl_substs.iter()) - .filter(|&(_, &k)| { - match k.unpack() { - GenericArgKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => { - !impl_generics.region_param(ebr, self).pure_wrt_drop - } - GenericArgKind::Type(&ty::TyS { kind: ty::Param(ref pt), .. }) => { - !impl_generics.type_param(pt, self).pure_wrt_drop - } - GenericArgKind::Const(&ty::Const { - val: ty::ConstKind::Param(ref pc), .. - }) => !impl_generics.const_param(pc, self).pure_wrt_drop, - GenericArgKind::Lifetime(_) - | GenericArgKind::Type(_) - | GenericArgKind::Const(_) => { - // Not a type, const or region param: this should be reported - // as an error. - false - } - } - }) - .map(|(&item_param, _)| item_param) - .collect(); - debug!("destructor_constraint({:?}) = {:?}", def.did, result); - result - } - - /// Returns `true` if `def_id` refers to a closure (e.g., `|x| x * 2`). Note - /// that closures have a `DefId`, but the closure *expression* also - /// has a `HirId` that is located within the context where the - /// closure appears (and, sadly, a corresponding `NodeId`, since - /// those are not yet phased out). The parent of the closure's - /// `DefId` will also be the context where it appears. - pub fn is_closure(self, def_id: DefId) -> bool { - self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr - } - - /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). - pub fn is_trait(self, def_id: DefId) -> bool { - self.def_kind(def_id) == Some(DefKind::Trait) - } - - /// Returns `true` if `def_id` refers to a trait alias (i.e., `trait Foo = ...;`), - /// and `false` otherwise. - pub fn is_trait_alias(self, def_id: DefId) -> bool { - self.def_kind(def_id) == Some(DefKind::TraitAlias) - } - - /// Returns `true` if this `DefId` refers to the implicit constructor for - /// a tuple struct like `struct Foo(u32)`, and `false` otherwise. - pub fn is_constructor(self, def_id: DefId) -> bool { - self.def_key(def_id).disambiguated_data.data == DefPathData::Ctor - } - - /// Given the def-ID of a fn or closure, returns the def-ID of - /// the innermost fn item that the closure is contained within. - /// This is a significant `DefId` because, when we do - /// type-checking, we type-check this fn item and all of its - /// (transitive) closures together. Therefore, when we fetch the - /// `typeck_tables_of` the closure, for example, we really wind up - /// fetching the `typeck_tables_of` the enclosing fn item. - pub fn closure_base_def_id(self, def_id: DefId) -> DefId { - let mut def_id = def_id; - while self.is_closure(def_id) { - def_id = self.parent(def_id).unwrap_or_else(|| { - bug!("closure {:?} has no parent", def_id); - }); - } - def_id - } - - /// Given the `DefId` and substs a closure, creates the type of - /// `self` argument that the closure expects. For example, for a - /// `Fn` closure, this would return a reference type `&T` where - /// `T = closure_ty`. - /// - /// Returns `None` if this closure's kind has not yet been inferred. - /// This should only be possible during type checking. - /// - /// Note that the return value is a late-bound region and hence - /// wrapped in a binder. - pub fn closure_env_ty( - self, - closure_def_id: DefId, - closure_substs: SubstsRef<'tcx>, - ) -> Option<ty::Binder<Ty<'tcx>>> { - let closure_ty = self.mk_closure(closure_def_id, closure_substs); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); - let closure_kind_ty = closure_substs.as_closure().kind_ty(closure_def_id, self); - let closure_kind = closure_kind_ty.to_opt_closure_kind()?; - let env_ty = match closure_kind { - ty::ClosureKind::Fn => self.mk_imm_ref(self.mk_region(env_region), closure_ty), - ty::ClosureKind::FnMut => self.mk_mut_ref(self.mk_region(env_region), closure_ty), - ty::ClosureKind::FnOnce => closure_ty, - }; - Some(ty::Binder::bind(env_ty)) - } - - /// Given the `DefId` of some item that has no type or const parameters, make - /// a suitable "empty substs" for it. - pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> SubstsRef<'tcx> { - InternalSubsts::for_item(self, item_def_id, |param, _| match param.kind { - GenericParamDefKind::Lifetime => self.lifetimes.re_erased.into(), - GenericParamDefKind::Type { .. } => { - bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) - } - GenericParamDefKind::Const { .. } => { - bug!("empty_substs_for_def_id: {:?} has const parameters", item_def_id) - } - }) - } - - /// Returns `true` if the node pointed to by `def_id` is a `static` item. - pub fn is_static(&self, def_id: DefId) -> bool { - self.static_mutability(def_id).is_some() - } - - /// Returns `true` if the node pointed to by `def_id` is a mutable `static` item. - pub fn is_mutable_static(&self, def_id: DefId) -> bool { - self.static_mutability(def_id) == Some(hir::Mutability::Mut) - } - - /// Get the type of the pointer to the static that we use in MIR. - pub fn static_ptr_ty(&self, def_id: DefId) -> Ty<'tcx> { - // Make sure that any constants in the static's type are evaluated. - let static_ty = self.normalize_erasing_regions(ty::ParamEnv::empty(), self.type_of(def_id)); - - if self.is_mutable_static(def_id) { - self.mk_mut_ptr(static_ty) - } else { - self.mk_imm_ref(self.lifetimes.re_erased, static_ty) - } - } - - /// Expands the given impl trait type, stopping if the type is recursive. - pub fn try_expand_impl_trait_type( - self, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> Result<Ty<'tcx>, Ty<'tcx>> { - use crate::ty::fold::TypeFolder; - - struct OpaqueTypeExpander<'tcx> { - // Contains the DefIds of the opaque types that are currently being - // expanded. When we expand an opaque type we insert the DefId of - // that type, and when we finish expanding that type we remove the - // its DefId. - seen_opaque_tys: FxHashSet<DefId>, - // Cache of all expansions we've seen so far. This is a critical - // optimization for some large types produced by async fn trees. - expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>, - primary_def_id: DefId, - found_recursion: bool, - tcx: TyCtxt<'tcx>, - } - - impl<'tcx> OpaqueTypeExpander<'tcx> { - fn expand_opaque_ty( - &mut self, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> Option<Ty<'tcx>> { - if self.found_recursion { - return None; - } - let substs = substs.fold_with(self); - if self.seen_opaque_tys.insert(def_id) { - let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) { - Some(expanded_ty) => expanded_ty, - None => { - let generic_ty = self.tcx.type_of(def_id); - let concrete_ty = generic_ty.subst(self.tcx, substs); - let expanded_ty = self.fold_ty(concrete_ty); - self.expanded_cache.insert((def_id, substs), expanded_ty); - expanded_ty - } - }; - self.seen_opaque_tys.remove(&def_id); - Some(expanded_ty) - } else { - // If another opaque type that we contain is recursive, then it - // will report the error, so we don't have to. - self.found_recursion = def_id == self.primary_def_id; - None - } - } - } - - impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Opaque(def_id, substs) = t.kind { - self.expand_opaque_ty(def_id, substs).unwrap_or(t) - } else if t.has_opaque_types() { - t.super_fold_with(self) - } else { - t - } - } - } - - let mut visitor = OpaqueTypeExpander { - seen_opaque_tys: FxHashSet::default(), - expanded_cache: FxHashMap::default(), - primary_def_id: def_id, - found_recursion: false, - tcx: self, - }; - let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap(); - if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } - } -} - -impl<'tcx> ty::TyS<'tcx> { - /// Returns the maximum value for the given numeric type (including `char`s) - /// or returns `None` if the type is not numeric. - pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> { - let val = match self.kind { - ty::Int(_) | ty::Uint(_) => { - let (size, signed) = int_size_and_signed(tcx, self); - let val = if signed { signed_max(size) as u128 } else { unsigned_max(size) }; - Some(val) - } - ty::Char => Some(std::char::MAX as u128), - ty::Float(fty) => Some(match fty { - ast::FloatTy::F32 => ::rustc_apfloat::ieee::Single::INFINITY.to_bits(), - ast::FloatTy::F64 => ::rustc_apfloat::ieee::Double::INFINITY.to_bits(), - }), - _ => None, - }; - val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) - } - - /// Returns the minimum value for the given numeric type (including `char`s) - /// or returns `None` if the type is not numeric. - pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> { - let val = match self.kind { - ty::Int(_) | ty::Uint(_) => { - let (size, signed) = int_size_and_signed(tcx, self); - let val = if signed { truncate(signed_min(size) as u128, size) } else { 0 }; - Some(val) - } - ty::Char => Some(0), - ty::Float(fty) => Some(match fty { - ast::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(), - ast::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(), - }), - _ => None, - }; - val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) - } - - /// Checks whether values of this type `T` are *moved* or *copied* - /// when referenced -- this amounts to a check for whether `T: - /// Copy`, but note that we **don't** consider lifetimes when - /// doing this check. This means that we may generate MIR which - /// does copies even when the type actually doesn't satisfy the - /// full requirements for the `Copy` trait (cc #29149) -- this - /// winds up being reported as an error during NLL borrow check. - pub fn is_copy_modulo_regions( - &'tcx self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - span: Span, - ) -> bool { - tcx.at(span).is_copy_raw(param_env.and(self)) - } - - /// Checks whether values of this type `T` have a size known at - /// compile time (i.e., whether `T: Sized`). Lifetimes are ignored - /// for the purposes of this check, so it can be an - /// over-approximation in generic contexts, where one can have - /// strange rules like `<T as Foo<'static>>::Bar: Sized` that - /// actually carry lifetime requirements. - pub fn is_sized(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_sized(tcx_at.tcx) || tcx_at.is_sized_raw(param_env.and(self)) - } - - /// Checks whether values of this type `T` implement the `Freeze` - /// trait -- frozen types are those that do not contain a - /// `UnsafeCell` anywhere. This is a language concept used to - /// distinguish "true immutability", which is relevant to - /// optimization as well as the rules around static values. Note - /// that the `Freeze` trait is not exposed to end users and is - /// effectively an implementation detail. - pub fn is_freeze( - &'tcx self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - span: Span, - ) -> bool { - self.is_trivially_freeze() || tcx.at(span).is_freeze_raw(param_env.and(self)) - } - - /// Fast path helper for testing if a type is `Freeze`. - /// - /// Returning true means the type is known to be `Freeze`. Returning - /// `false` means nothing -- could be `Freeze`, might not be. - fn is_trivially_freeze(&self) -> bool { - match self.kind { - ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Bool - | ty::Char - | ty::Str - | ty::Never - | ty::Ref(..) - | ty::RawPtr(_) - | ty::FnDef(..) - | ty::Error - | ty::FnPtr(_) => true, - ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_freeze), - ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(), - ty::Adt(..) - | ty::Bound(..) - | ty::Closure(..) - | ty::Dynamic(..) - | ty::Foreign(_) - | ty::Generator(..) - | ty::GeneratorWitness(_) - | ty::Infer(_) - | ty::Opaque(..) - | ty::Param(_) - | ty::Placeholder(_) - | ty::Projection(_) - | ty::UnnormalizedProjection(_) => false, - } - } - - /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely - /// non-copy and *might* have a destructor attached; if it returns - /// `false`, then `ty` definitely has no destructor (i.e., no drop glue). - /// - /// (Note that this implies that if `ty` has a destructor attached, - /// then `needs_drop` will definitely return `true` for `ty`.) - /// - /// Note that this method is used to check eligible types in unions. - #[inline] - pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - // Avoid querying in simple cases. - match needs_drop_components(self, &tcx.data_layout) { - Err(AlwaysRequiresDrop) => true, - Ok(components) => { - let query_ty = match *components { - [] => return false, - // If we've got a single component, call the query with that - // to increase the chance that we hit the query cache. - [component_ty] => component_ty, - _ => self, - }; - // This doesn't depend on regions, so try to minimize distinct - // query keys used. - let erased = tcx.normalize_erasing_regions(param_env, query_ty); - tcx.needs_drop_raw(param_env.and(erased)) - } - } - } - - pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.kind, &b.kind) { - (&Adt(did_a, substs_a), &Adt(did_b, substs_b)) => { - if did_a != did_b { - return false; - } - - substs_a.types().zip(substs_b.types()).all(|(a, b)| Self::same_type(a, b)) - } - _ => a == b, - } - } - - /// Check whether a type is representable. This means it cannot contain unboxed - /// structural recursion. This check is needed for structs and enums. - pub fn is_representable(&'tcx self, tcx: TyCtxt<'tcx>, sp: Span) -> Representability { - // Iterate until something non-representable is found - fn fold_repr<It: Iterator<Item = Representability>>(iter: It) -> Representability { - iter.fold(Representability::Representable, |r1, r2| match (r1, r2) { - (Representability::SelfRecursive(v1), Representability::SelfRecursive(v2)) => { - Representability::SelfRecursive(v1.into_iter().chain(v2).collect()) - } - (r1, r2) => cmp::max(r1, r2), - }) - } - - fn are_inner_types_recursive<'tcx>( - tcx: TyCtxt<'tcx>, - sp: Span, - seen: &mut Vec<Ty<'tcx>>, - representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>, - ty: Ty<'tcx>, - ) -> Representability { - match ty.kind { - Tuple(..) => { - // Find non representable - fold_repr(ty.tuple_fields().map(|ty| { - is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty) - })) - } - // Fixed-length vectors. - // FIXME(#11924) Behavior undecided for zero-length vectors. - Array(ty, _) => { - is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty) - } - Adt(def, substs) => { - // Find non representable fields with their spans - fold_repr(def.all_fields().map(|field| { - let ty = field.ty(tcx, substs); - let span = tcx.hir().span_if_local(field.did).unwrap_or(sp); - match is_type_structurally_recursive( - tcx, - span, - seen, - representable_cache, - ty, - ) { - Representability::SelfRecursive(_) => { - Representability::SelfRecursive(vec![span]) - } - x => x, - } - })) - } - Closure(..) => { - // this check is run on type definitions, so we don't expect - // to see closure types - bug!("requires check invoked on inapplicable type: {:?}", ty) - } - _ => Representability::Representable, - } - } - - fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: &'tcx ty::AdtDef) -> bool { - match ty.kind { - Adt(ty_def, _) => ty_def == def, - _ => false, - } - } - - // Does the type `ty` directly (without indirection through a pointer) - // contain any types on stack `seen`? - fn is_type_structurally_recursive<'tcx>( - tcx: TyCtxt<'tcx>, - sp: Span, - seen: &mut Vec<Ty<'tcx>>, - representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>, - ty: Ty<'tcx>, - ) -> Representability { - debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp); - if let Some(representability) = representable_cache.get(ty) { - debug!( - "is_type_structurally_recursive: {:?} {:?} - (cached) {:?}", - ty, sp, representability - ); - return representability.clone(); - } - - let representability = - is_type_structurally_recursive_inner(tcx, sp, seen, representable_cache, ty); - - representable_cache.insert(ty, representability.clone()); - representability - } - - fn is_type_structurally_recursive_inner<'tcx>( - tcx: TyCtxt<'tcx>, - sp: Span, - seen: &mut Vec<Ty<'tcx>>, - representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>, - ty: Ty<'tcx>, - ) -> Representability { - match ty.kind { - Adt(def, _) => { - { - // Iterate through stack of previously seen types. - let mut iter = seen.iter(); - - // The first item in `seen` is the type we are actually curious about. - // We want to return SelfRecursive if this type contains itself. - // It is important that we DON'T take generic parameters into account - // for this check, so that Bar<T> in this example counts as SelfRecursive: - // - // struct Foo; - // struct Bar<T> { x: Bar<Foo> } - - if let Some(&seen_type) = iter.next() { - if same_struct_or_enum(seen_type, def) { - debug!("SelfRecursive: {:?} contains {:?}", seen_type, ty); - return Representability::SelfRecursive(vec![sp]); - } - } - - // We also need to know whether the first item contains other types - // that are structurally recursive. If we don't catch this case, we - // will recurse infinitely for some inputs. - // - // It is important that we DO take generic parameters into account - // here, so that code like this is considered SelfRecursive, not - // ContainsRecursive: - // - // struct Foo { Option<Option<Foo>> } - - for &seen_type in iter { - if ty::TyS::same_type(ty, seen_type) { - debug!("ContainsRecursive: {:?} contains {:?}", seen_type, ty); - return Representability::ContainsRecursive; - } - } - } - - // For structs and enums, track all previously seen types by pushing them - // onto the 'seen' stack. - seen.push(ty); - let out = are_inner_types_recursive(tcx, sp, seen, representable_cache, ty); - seen.pop(); - out - } - _ => { - // No need to push in other cases. - are_inner_types_recursive(tcx, sp, seen, representable_cache, ty) - } - } - } - - debug!("is_type_representable: {:?}", self); - - // To avoid a stack overflow when checking an enum variant or struct that - // contains a different, structurally recursive type, maintain a stack - // of seen types and check recursion for each of them (issues #3008, #3779). - let mut seen: Vec<Ty<'_>> = Vec::new(); - let mut representable_cache = FxHashMap::default(); - let r = is_type_structurally_recursive(tcx, sp, &mut seen, &mut representable_cache, self); - debug!("is_type_representable: {:?} is {:?}", self, r); - r - } - - /// Peel off all reference types in this type until there are none left. - /// - /// This method is idempotent, i.e. `ty.peel_refs().peel_refs() == ty.peel_refs()`. - /// - /// # Examples - /// - /// - `u8` -> `u8` - /// - `&'a mut u8` -> `u8` - /// - `&'a &'b u8` -> `u8` - /// - `&'a *const &'b u8 -> *const &'b u8` - pub fn peel_refs(&'tcx self) -> Ty<'tcx> { - let mut ty = self; - while let Ref(_, inner_ty, _) = ty.kind { - ty = inner_ty; - } - ty - } -} - -pub enum ExplicitSelf<'tcx> { - ByValue, - ByReference(ty::Region<'tcx>, hir::Mutability), - ByRawPointer(hir::Mutability), - ByBox, - Other, -} - -impl<'tcx> ExplicitSelf<'tcx> { - /// Categorizes an explicit self declaration like `self: SomeType` - /// into either `self`, `&self`, `&mut self`, `Box<self>`, or - /// `Other`. - /// This is mainly used to require the arbitrary_self_types feature - /// in the case of `Other`, to improve error messages in the common cases, - /// and to make `Other` non-object-safe. - /// - /// Examples: - /// - /// ``` - /// impl<'a> Foo for &'a T { - /// // Legal declarations: - /// fn method1(self: &&'a T); // ExplicitSelf::ByReference - /// fn method2(self: &'a T); // ExplicitSelf::ByValue - /// fn method3(self: Box<&'a T>); // ExplicitSelf::ByBox - /// fn method4(self: Rc<&'a T>); // ExplicitSelf::Other - /// - /// // Invalid cases will be caught by `check_method_receiver`: - /// fn method_err1(self: &'a mut T); // ExplicitSelf::Other - /// fn method_err2(self: &'static T) // ExplicitSelf::ByValue - /// fn method_err3(self: &&T) // ExplicitSelf::ByReference - /// } - /// ``` - /// - pub fn determine<P>(self_arg_ty: Ty<'tcx>, is_self_ty: P) -> ExplicitSelf<'tcx> - where - P: Fn(Ty<'tcx>) -> bool, - { - use self::ExplicitSelf::*; - - match self_arg_ty.kind { - _ if is_self_ty(self_arg_ty) => ByValue, - ty::Ref(region, ty, mutbl) if is_self_ty(ty) => ByReference(region, mutbl), - ty::RawPtr(ty::TypeAndMut { ty, mutbl }) if is_self_ty(ty) => ByRawPointer(mutbl), - ty::Adt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox, - _ => Other, - } - } -} - -/// Returns a list of types such that the given type needs drop if and only if -/// *any* of the returned types need drop. Returns `Err(AlwaysRequiresDrop)` if -/// this type always needs drop. -pub fn needs_drop_components( - ty: Ty<'tcx>, - target_layout: &TargetDataLayout, -) -> Result<SmallVec<[Ty<'tcx>; 2]>, AlwaysRequiresDrop> { - match ty.kind { - ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - | ty::Bool - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Never - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Char - | ty::GeneratorWitness(..) - | ty::RawPtr(_) - | ty::Ref(..) - | ty::Str => Ok(SmallVec::new()), - - // Foreign types can never have destructors. - ty::Foreign(..) => Ok(SmallVec::new()), - - // Pessimistically assume that all generators will require destructors - // as we don't know if a destructor is a noop or not until after the MIR - // state transformation pass. - ty::Generator(..) | ty::Dynamic(..) | ty::Error => Err(AlwaysRequiresDrop), - - ty::Slice(ty) => needs_drop_components(ty, target_layout), - ty::Array(elem_ty, size) => { - match needs_drop_components(elem_ty, target_layout) { - Ok(v) if v.is_empty() => Ok(v), - res => match size.val.try_to_bits(target_layout.pointer_size) { - // Arrays of size zero don't need drop, even if their element - // type does. - Some(0) => Ok(SmallVec::new()), - Some(_) => res, - // We don't know which of the cases above we are in, so - // return the whole type and let the caller decide what to - // do. - None => Ok(smallvec![ty]), - }, - } - } - // If any field needs drop, then the whole tuple does. - ty::Tuple(..) => ty.tuple_fields().try_fold(SmallVec::new(), move |mut acc, elem| { - acc.extend(needs_drop_components(elem, target_layout)?); - Ok(acc) - }), - - // These require checking for `Copy` bounds or `Adt` destructors. - ty::Adt(..) - | ty::Projection(..) - | ty::UnnormalizedProjection(..) - | ty::Param(_) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Opaque(..) - | ty::Infer(_) - | ty::Closure(..) => Ok(smallvec![ty]), - } -} - -#[derive(Copy, Clone, Debug, HashStable, RustcEncodable, RustcDecodable)] -pub struct AlwaysRequiresDrop; diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs deleted file mode 100644 index da08fbcf144..00000000000 --- a/src/librustc/ty/walk.rs +++ /dev/null @@ -1,138 +0,0 @@ -//! An iterator over the type substructure. -//! WARNING: this does not keep track of the region depth. - -use crate::ty::{self, Ty}; -use smallvec::{self, SmallVec}; - -// The TypeWalker's stack is hot enough that it's worth going to some effort to -// avoid heap allocations. -pub type TypeWalkerArray<'tcx> = [Ty<'tcx>; 8]; -pub type TypeWalkerStack<'tcx> = SmallVec<TypeWalkerArray<'tcx>>; - -pub struct TypeWalker<'tcx> { - stack: TypeWalkerStack<'tcx>, - last_subtree: usize, -} - -impl<'tcx> TypeWalker<'tcx> { - pub fn new(ty: Ty<'tcx>) -> TypeWalker<'tcx> { - TypeWalker { stack: smallvec![ty], last_subtree: 1 } - } - - /// Skips the subtree of types corresponding to the last type - /// returned by `next()`. - /// - /// Example: Imagine you are walking `Foo<Bar<int>, usize>`. - /// - /// ``` - /// let mut iter: TypeWalker = ...; - /// iter.next(); // yields Foo - /// iter.next(); // yields Bar<int> - /// iter.skip_current_subtree(); // skips int - /// iter.next(); // yields usize - /// ``` - pub fn skip_current_subtree(&mut self) { - self.stack.truncate(self.last_subtree); - } -} - -impl<'tcx> Iterator for TypeWalker<'tcx> { - type Item = Ty<'tcx>; - - fn next(&mut self) -> Option<Ty<'tcx>> { - debug!("next(): stack={:?}", self.stack); - match self.stack.pop() { - None => None, - Some(ty) => { - self.last_subtree = self.stack.len(); - push_subtypes(&mut self.stack, ty); - debug!("next: stack={:?}", self.stack); - Some(ty) - } - } - } -} - -pub fn walk_shallow(ty: Ty<'_>) -> smallvec::IntoIter<TypeWalkerArray<'_>> { - let mut stack = SmallVec::new(); - push_subtypes(&mut stack, ty); - stack.into_iter() -} - -// We push types on the stack in reverse order so as to -// maintain a pre-order traversal. As of the time of this -// writing, the fact that the traversal is pre-order is not -// known to be significant to any code, but it seems like the -// natural order one would expect (basically, the order of the -// types as they are written). -fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { - match parent_ty.kind { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Infer(_) - | ty::Param(_) - | ty::Never - | ty::Error - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Foreign(..) => {} - ty::Array(ty, len) => { - if let ty::ConstKind::Unevaluated(_, substs, promoted) = len.val { - assert!(promoted.is_none()); - stack.extend(substs.types().rev()); - } - stack.push(len.ty); - stack.push(ty); - } - ty::Slice(ty) => { - stack.push(ty); - } - ty::RawPtr(ref mt) => { - stack.push(mt.ty); - } - ty::Ref(_, ty, _) => { - stack.push(ty); - } - ty::Projection(ref data) | ty::UnnormalizedProjection(ref data) => { - stack.extend(data.substs.types().rev()); - } - ty::Dynamic(ref obj, ..) => { - stack.extend(obj.iter().rev().flat_map(|predicate| { - let (substs, opt_ty) = match *predicate.skip_binder() { - ty::ExistentialPredicate::Trait(tr) => (tr.substs, None), - ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)), - ty::ExistentialPredicate::AutoTrait(_) => - // Empty iterator - { - (ty::InternalSubsts::empty(), None) - } - }; - - substs.types().rev().chain(opt_ty) - })); - } - ty::Adt(_, substs) | ty::Opaque(_, substs) => { - stack.extend(substs.types().rev()); - } - ty::Closure(_, ref substs) | ty::Generator(_, ref substs, _) => { - stack.extend(substs.types().rev()); - } - ty::GeneratorWitness(ts) => { - stack.extend(ts.skip_binder().iter().cloned().rev()); - } - ty::Tuple(..) => { - stack.extend(parent_ty.tuple_fields().rev()); - } - ty::FnDef(_, substs) => { - stack.extend(substs.types().rev()); - } - ty::FnPtr(sig) => { - stack.push(sig.skip_binder().output()); - stack.extend(sig.skip_binder().inputs().iter().cloned().rev()); - } - } -} diff --git a/src/librustc/util/bug.rs b/src/librustc/util/bug.rs deleted file mode 100644 index c12b2859f72..00000000000 --- a/src/librustc/util/bug.rs +++ /dev/null @@ -1,41 +0,0 @@ -// These functions are used by macro expansion for bug! and span_bug! - -use crate::ty::tls; -use rustc_span::{MultiSpan, Span}; -use std::fmt; - -#[cold] -#[inline(never)] -pub fn bug_fmt(file: &'static str, line: u32, args: fmt::Arguments<'_>) -> ! { - // this wrapper mostly exists so I don't have to write a fully - // qualified path of None::<Span> inside the bug!() macro definition - opt_span_bug_fmt(file, line, None::<Span>, args); -} - -#[cold] -#[inline(never)] -pub fn span_bug_fmt<S: Into<MultiSpan>>( - file: &'static str, - line: u32, - span: S, - args: fmt::Arguments<'_>, -) -> ! { - opt_span_bug_fmt(file, line, Some(span), args); -} - -fn opt_span_bug_fmt<S: Into<MultiSpan>>( - file: &'static str, - line: u32, - span: Option<S>, - args: fmt::Arguments<'_>, -) -> ! { - tls::with_opt(move |tcx| { - let msg = format!("{}:{}: {}", file, line, args); - match (tcx, span) { - (Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, &msg), - (Some(tcx), None) => tcx.sess.diagnostic().bug(&msg), - (None, _) => panic!(msg), - } - }); - unreachable!(); -} diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs deleted file mode 100644 index 19b43bfd162..00000000000 --- a/src/librustc/util/common.rs +++ /dev/null @@ -1,71 +0,0 @@ -#![allow(non_camel_case_types)] - -use rustc_data_structures::sync::Lock; - -use std::fmt::Debug; -use std::time::{Duration, Instant}; - -#[cfg(test)] -mod tests; - -pub use rustc_errors::ErrorReported; - -pub fn to_readable_str(mut val: usize) -> String { - let mut groups = vec![]; - loop { - let group = val % 1000; - - val /= 1000; - - if val == 0 { - groups.push(group.to_string()); - break; - } else { - groups.push(format!("{:03}", group)); - } - } - - groups.reverse(); - - groups.join("_") -} - -pub fn record_time<T, F>(accu: &Lock<Duration>, f: F) -> T -where - F: FnOnce() -> T, -{ - let start = Instant::now(); - let rv = f(); - let duration = start.elapsed(); - let mut accu = accu.lock(); - *accu = *accu + duration; - rv -} - -pub fn indent<R, F>(op: F) -> R -where - R: Debug, - F: FnOnce() -> R, -{ - // Use in conjunction with the log post-processor like `src/etc/indenter` - // to make debug output more readable. - debug!(">>"); - let r = op(); - debug!("<< (Result = {:?})", r); - r -} - -pub struct Indenter { - _cannot_construct_outside_of_this_module: (), -} - -impl Drop for Indenter { - fn drop(&mut self) { - debug!("<<"); - } -} - -pub fn indenter() -> Indenter { - debug!(">>"); - Indenter { _cannot_construct_outside_of_this_module: () } -} diff --git a/src/librustc/util/common/tests.rs b/src/librustc/util/common/tests.rs deleted file mode 100644 index 9a9fb203c62..00000000000 --- a/src/librustc/util/common/tests.rs +++ /dev/null @@ -1,14 +0,0 @@ -use super::*; - -#[test] -fn test_to_readable_str() { - assert_eq!("0", to_readable_str(0)); - assert_eq!("1", to_readable_str(1)); - assert_eq!("99", to_readable_str(99)); - assert_eq!("999", to_readable_str(999)); - assert_eq!("1_000", to_readable_str(1_000)); - assert_eq!("1_001", to_readable_str(1_001)); - assert_eq!("999_999", to_readable_str(999_999)); - assert_eq!("1_000_000", to_readable_str(1_000_000)); - assert_eq!("1_234_567", to_readable_str(1_234_567)); -} |
